Skip to content

Commit

Permalink
Merge pull request #1 from gurukami/dev
Browse files Browse the repository at this point in the history
Stable version
  • Loading branch information
Nerufa authored Mar 9, 2019
2 parents 64d22af + bd00ecb commit 8733757
Show file tree
Hide file tree
Showing 27 changed files with 10,006 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vendor
15 changes: 15 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
language: go

matrix:
include:
- go: 1.10.x
- go: 1.11.x
- go: 1.12.x

before_install:
- mkdir -p bin
- curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck
- chmod +x bin/shellcheck
script:
- PATH=$PATH:$PWD/bin go test -v ./...
- go build
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.
151 changes: 150 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,150 @@
# typ
# Typ

[![Build Status](https://travis-ci.org/gurukami/typ.svg "Travis CI status")](https://travis-ci.org/gurukami/typ)
[![GoDoc](https://godoc.org/github.com/gurukami/typ?status.svg)](https://godoc.org/github.com/gurukami/typ)

Typ is a library providing a powerful interface to impressive user experience with conversion and fetching data from built-in types in Golang

## Features

* Safe conversion along built-in types like as `bool`, `int`, `int8`, `int16`, `int32`, `int64`, `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `float32`, `float64`, `complex64`, `complex128`, `string`
* Null types for all primitive types with supported interfaces: ```json.Unmarshaler```, ```json.Marshaler```, ```sql.Scanner```, ```driver.Valuer```
* Value retriever for multidimensional unstructured data from interface
* Conversion functions present via interface (reflection) and native types for better performance
* Some humanize string conversion functions

## Installation

Use ```go get``` to install the latest version of the library.

```go
go get -u github.com/gurukami/typ
```

Then include package in your application and enjoy.

```go
import "github.com/gurukami/typ"
```
## Usage

**Of(interface{})** conversion from interface value to built-in type

```go
// typ.Of(v interface{}, options ...Option).{Type}(defaultValue ...{Type})
//
// Where {Type} any of
// Bool,
// Int, Int8, Int16, Int32, Int64,
// Uint, Uint8, Uint16, Uint32, Uint64,
// Float32, Float,
// Complex64, Complex,
// String
//
// All methods for conversion returns Null{Type} struct with helpful methods & fields
//
// fields:
// P - pointer to value
// Error - conversion error
//
// methods:
// V() - value of type
// Present() - determines whether a value has been set
// Valid() - determines whether a value has been valid (without error)
//
// Scan(value interface{}) | sql.Scanner
// Value() (driver.Value, error) | driver.Valuer
//
// UnmarshalJSON(b []byte) error | json.Unmarshaler
// MarshalJSON() ([]byte, error) | json.Marshaler

// Valid
nv := typ.Of(3.1415926535, typ.FmtByte('g'), typ.Precision(4)).String()
fmt.Printf("Value: %v, Valid: %v, Present: %v, Error: %v\n", nv.V(), nv.Valid(), nv.Present(), nv.Error)
// Output: Value: 3.142, Valid: true, Present: true, Error: <nil>

// Not valid
nv = typ.Of(3.1415926535).Int()
fmt.Printf("Value: %v, Valid: %v, Present: %v, Error: %v\n", nv.V(), nv.Valid(), nv.Present(), nv.Error)
// Output: Value: 3, Valid: false, Present: true, Error: value can't safely convert
```

**Native conversion without `reflection` when type is know**

```go
// For the best performance always use this way if you know about exact type
//
// typ.{FromType}{ToType}(value , [options ...{FromType}{ToType}Option]).V()
//
// Where {FromType}, {ToType} any of
// Bool,
// Int, Int8, Int16, Int32, Int64,
// Uint, Uint8, Uint16, Uint32, Uint64,
// Float32, Float,
// Complex64, Complex,
// String
//
// All methods for conversion returns Null{Type} struct with helpful methods & fields, additional info you can read in example above

// Valid
nv := typ.FloatString(3.1415926535, typ.FloatStringFmtByte('g'), typ.FloatStringPrecision(4))
fmt.Printf("Value: %v, Valid: %v, Present: %v, Error: %v\n", nv.V(), nv.Valid(), nv.Present(), nv.Error)
// Output: Value: 3.142, Valid: true, Present: true, Error: <nil>

// Not valid
nv = typ.FloatInt(3.1415926535)
fmt.Printf("Value: %v, Valid: %v, Present: %v, Error: %v\n", nv.V(), nv.Valid(), nv.Present(), nv.Error)
// Output: Value: 3, Valid: false, Present: true, Error: value can't safely convert
```

**Retrieve multidimensional unstructured data from interface**

```go
data := map[int]interface{}{
0: []interface{}{
0: map[string]int{
"0": 42,
},
},
}

// Instead of do something like this
// data[0].([]interface{})[0].(map[string]int)["0”]
// and not caught a panic
// use this

// Value exists
nv := typ.Of(data).Get(0, 0, "0").Interface()
fmt.Printf("Value: %v, Valid: %v, Present: %v, Error: %v\n", nv.V(), nv.Valid(), nv.Present(), nv.Error)
// Output: Value: 42, Valid: true, Present: true, Error: <nil>

// Value not exists
nv = typ.Of(data).Get(3, 7, "5").Interface()
fmt.Printf("Value: %v, Valid: %v, Present: %v, Error: %v\n", nv.V(), nv.Valid(), nv.Present(), nv.Error)
// Output: Value: <nil>, Valid: false, Present: false, Error: out of bounds on given data
```

**Rules of safely type conversion along types**

| From / to | Bool | Int* | String | Uint* | Float* | Complex* |
|----------|:-------------:|:------:|:---:|:---:|:---:|:---:|
| Bool | + | + | + | + | + | + |
| Int* | + | + | `formatting` | `>= 0` | `24bit or 53bit` | `real`, `24bit or 53bit` |
| String | `parsing` | `parsing` | + | `parsing` | `parsing` | `parsing` |
| Uint* | + | `63bit` | `formatting` | + | `24bit or 53bit` | `24bit or 53bit` |
| Float* | + | `24bit or 53bit` | `formatting` | `24bit or 53bit` | + | + |
| Complex* | + | `real`, `24bit or 53bit` | + | `>= 0`, `real`, `24bit or 53bit` | `real` | + |

\* based on bit size capacity, `8,16,32,64` for `Int`,`Uint`; `32,64` for `Float`,`Complex`

## Donation for amazing goal

I like airplanes and i want to get private pilot licence, and i believe you can help me to make my dream come true :)

[ >>>>>>>>>> **Make a dream come true** <<<<<<<<<< ](https://gist.github.com/Nerufa/0d868899d628b1b105f74b6da501bc1f)


## License

The MIT license
Copyright (c) 2019 Gurukami
107 changes: 107 additions & 0 deletions booleans.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package typ

import (
"reflect"
"strings"
)

// Convert interface value to bool.
// Returns true for any non-zero values
func (t *Type) Bool() (nv NullBool) {
if nv.Error = t.err; t.err != nil {
return
}
return t.toBool(false)
}

// Convert interface value to bool.
// Returns false for string 'false' in case-insensitive mode or string equals '0', for other types
// returns true only for positive values
func (t *Type) BoolHumanize() (nv NullBool) {
if nv.Error = t.err; t.err != nil {
return
}
switch {
case t.IsString(true):
bf := strings.EqualFold("false", t.rv.String()) || t.rv.String() == "0"
bt := strings.EqualFold("true", t.rv.String()) || t.rv.String() == "1"
if !bf && !bt {
nv.Error = ErrUnexpectedValue
}
nv.P = &bt
return
case t.IsBool(true):
v := t.rv.Bool()
nv.P = &v
return
default:
return t.toBool(true)
}
}

// Convert interface value to bool.
// Returns true only for positive values
func (t *Type) BoolPositive() (nv NullBool) {
if nv.Error = t.err; t.err != nil {
return
}
return t.toBool(true)
}

// Convert interface value to bool.
// It check positive values if argument "positive" is true, otherwise always true for any non-zero values
func (t *Type) toBool(positive bool) (nv NullBool) {
var v bool
switch {
case t.IsBool(true):
v = t.rv.Bool()
goto end
case t.IsString(true):
v = t.rv.Len() != 0
goto end
case t.IsInt(true):
vInt := t.rv.Int()
v = (vInt < 0 && !positive) || vInt > 0
goto end
case t.IsUint(true):
vUint := t.rv.Uint()
v = (vUint < 0 && !positive) || vUint > 0
goto end
case t.IsFloat(true):
vFloat := t.rv.Float()
v = (vFloat != 0 && !positive) || vFloat > 0
goto end
case t.IsComplex(true):
value := t.rv.Complex()
fr := real(value)
v = (fr != 0 && !positive) || fr > 0
goto end
default:
if positive {
switch t.rv.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
v = t.rv.Len() > 0
goto end
}
}
nv = t.Empty()
*nv.P = !*nv.P
return
}
end:
nv.P = &v
return
}

// Convert value from string to bool.
// Returns false for string 'false' in case-insensitive mode or string equals '0'
func StringBoolHumanize(from string) (nv NullBool) {
bf := strings.EqualFold("false", from) || from == "0"
bt := strings.EqualFold("true", from) || from == "1"
if !bf && !bt {
nv.Error = ErrUnexpectedValue
return
}
nv.P = &bt
return
}
Loading

0 comments on commit 8733757

Please sign in to comment.