diff --git a/cast.go b/cast.go new file mode 100644 index 0000000..4bd3ba3 --- /dev/null +++ b/cast.go @@ -0,0 +1,48 @@ +// Copyright © 2014 Steve Francia . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package cast + +import "time" + +func ToBool(i interface{}) bool { + v, _ := ToBoolE(i) + return v +} + +func ToTime(i interface{}) time.Time { + v, _ := ToTimeE(i) + return v +} + +func ToFloat64(i interface{}) float64 { + v, _ := ToFloat64E(i) + return v +} + +func ToInt(i interface{}) int { + v, _ := ToIntE(i) + return v +} + +func ToString(i interface{}) string { + v, _ := ToStringE(i) + return v +} + +func ToStringMapString(i interface{}) map[string]string { + v, _ := ToStringMapStringE(i) + return v +} + +func ToStringMap(i interface{}) map[string]interface{} { + v, _ := ToStringMapE(i) + return v +} + +func ToStringSlice(i interface{}) []string { + v, _ := ToStringSliceE(i) + return v +} diff --git a/cast_test.go b/cast_test.go new file mode 100644 index 0000000..5a6dc3d --- /dev/null +++ b/cast_test.go @@ -0,0 +1,26 @@ +// Copyright © 2014 Steve Francia . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package cast + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestToInt(t *testing.T) { + var eight interface{} = 8 + assert.Equal(t, ToInt(8), 8) + assert.Equal(t, ToInt("8"), 8) + assert.Equal(t, ToInt(true), 1) + assert.Equal(t, ToInt(false), 0) + assert.Equal(t, ToInt(eight), 8) +} + +func TestMaps(t *testing.T) { + var taxonomies = map[interface{}]interface{}{"tag": "tags", "group": "groups"} + assert.Equal(t, ToStringMap(taxonomies), map[string]interface{}{"tag": "tags", "group": "groups"}) +} diff --git a/caste.go b/caste.go new file mode 100644 index 0000000..49025fc --- /dev/null +++ b/caste.go @@ -0,0 +1,199 @@ +// Copyright © 2014 Steve Francia . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package cast + +import ( + "errors" + "fmt" + "strconv" + "time" + + jww "github.com/spf13/jwalterweatherman" +) + +func ToTimeE(i interface{}) (tim time.Time, ok bool) { + switch s := i.(type) { + case time.Time: + return s, true + case string: + d, e := StringToDate(s) + if e == nil { + return d, true + } + + jww.ERROR.Println("Could not parse Date/Time format:", e) + return time.Time{}, false + default: + jww.ERROR.Printf("Unable to Cast %#v to Time", i) + return time.Time{}, false + } + + return time.Time{}, false +} + +func ToBoolE(i interface{}) (bool, bool) { + switch b := i.(type) { + case bool: + return b, true + case nil: + return false, true + case int: + if i.(int) > 0 { + return true, true + } + return false, true + default: + return false, false + jww.ERROR.Printf("Unable to Cast %#v to bool", i) + } + + return false, false +} + +func ToStringMapStringE(i interface{}) (map[string]string, bool) { + var m = map[string]string{} + + switch v := i.(type) { + case map[interface{}]interface{}: + for k, val := range v { + m[ToString(k)] = ToString(val) + } + default: + return m, false + } + + return m, true +} + +func ToStringMapE(i interface{}) (map[string]interface{}, bool) { + var m = map[string]interface{}{} + + switch v := i.(type) { + case map[interface{}]interface{}: + for k, val := range v { + m[ToString(k)] = val + } + default: + return m, false + } + + return m, true +} + +func ToStringSliceE(i interface{}) ([]string, bool) { + var a []string + + switch v := i.(type) { + case []interface{}: + for _, u := range v { + a = append(a, ToString(u)) + } + default: + return a, false + } + + return a, true +} + +func ToFloat64E(i interface{}) (float64, bool) { + switch s := i.(type) { + case float64: + return s, true + case float32: + return float64(s), true + + case string: + v, err := strconv.ParseFloat(s, 64) + if err == nil { + return float64(v), true + } else { + jww.ERROR.Printf("Unable to Cast %#v to float", i) + jww.ERROR.Println(err) + } + + default: + jww.ERROR.Printf("Unable to Cast %#v to float", i) + } + + return 0.0, false +} + +func ToIntE(i interface{}) (int, bool) { + switch s := i.(type) { + case int: + return s, true + case int64: + return int(s), true + case int32: + return int(s), true + case int16: + return int(s), true + case int8: + return int(s), true + case string: + v, err := strconv.ParseInt(s, 0, 0) + if err == nil { + return int(v), true + } else { + jww.ERROR.Printf("Unable to Cast %#v to int", i) + jww.ERROR.Println(err) + } + case bool: + if bool(s) { + return 1, true + } else { + return 0, true + } + default: + jww.ERROR.Printf("Unable to Cast %#v to int", i) + } + + return 0, false +} + +func ToStringE(i interface{}) (string, bool) { + switch s := i.(type) { + case string: + return s, true + case float64: + return strconv.FormatFloat(i.(float64), 'f', -1, 64), true + case int: + return strconv.FormatInt(int64(i.(int)), 10), true + case nil: + return "", true + default: + jww.ERROR.Printf("Unable to Cast %#v to string", i) + } + + return "", false +} + +func StringToDate(s string) (time.Time, error) { + return parseDateWith(s, []string{ + time.RFC3339, + "2006-01-02T15:04:05", // iso8601 without timezone + time.RFC1123Z, + time.RFC1123, + time.RFC822Z, + time.RFC822, + time.ANSIC, + time.UnixDate, + time.RubyDate, + "2006-01-02 15:04:05Z07:00", + "02 Jan 06 15:04 MST", + "2006-01-02", + "02 Jan 2006", + }) +} + +func parseDateWith(s string, dates []string) (d time.Time, e error) { + for _, dateType := range dates { + if d, e = time.Parse(dateType, s); e == nil { + return + } + } + return d, errors.New(fmt.Sprintf("Unable to parse date: %s", s)) +}