diff --git a/README.md b/README.md index 7ba7be9..e35f373 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,72 @@ cast ==== -easy casting from one type to another in Go +Easy and safe casting from one type to another in Go + +Don’t Panic! ... Cast + +## What is Cast? + +Cast is a library to convert between different go types in a consistent and easy way. + +Cast provides simple functions to easily convert a number to a string, an +interface into a bool, etc. Cast does this intelligently when an obvious +conversion is possible. It doesn’t make any attempts to guess what you meant, +for example you can only convert a string to an int when it is a string +representation of an int such as “8”. Cast was developed for use in +[Hugo](http://hugo.spf13.com), a website engine which uses YAML, TOML or JSON +for meta data. + +## Why use Cast? + +When working with dynamic data in Go you often need to cast or convert the data +from one type into another. Cast goes beyond just using type assertion (though +it uses that when possible) to provide a very straightforward and convenient +library. + +If you are working with interfaces to handle things like dynamic content +you’ll need an easy way to convert an interface into a given type. This +is the library for you. + +If you are taking in data from YAML, TOML or JSON or other formats which lack +full types, then Cast is the library for you. + +## Usage + +Cast provides a handful of To_____ methods. These methods will always return +the desired type. **If input is provided that will not convert to that type, the +0 or nil value for that type will be returned**. + +Cast also provides identical methods To_____E. These return the same result as +the To_____ methods, plus an additional bool which tells you if it successfully +converted. Using these methods you can tell the difference between when the +input matched the zero value or when the conversion failed and the zero value +was returned. + +The following examples are merely a sample of what is available. Please review +the code for a complete set. + +### Example ‘ToString’: + + cast.ToString("mayonegg") // "mayonegg" + cast.ToString(8) // "8" + cast.ToString(8.31) // "8.31" + cast.ToString([]byte("one time")) // "one time" + cast.ToString(nil) // "" + + var foo interface{} = "one more time" + cast.ToString(foo) // "one more time" + + +### Example ‘ToInt’: + + cast.ToInt(8) // 8 + cast.ToInt(8.31) // 8 + cast.ToInt("8") // 8 + cast.ToInt(true) // 1 + cast.ToInt(false) // 0 + + var eight interface{} = 8 + cast.ToInt(eight) // 8 + cast.ToInt(nil) // 0 + diff --git a/cast_test.go b/cast_test.go index 5a6dc3d..c9f642c 100644 --- a/cast_test.go +++ b/cast_test.go @@ -14,12 +14,22 @@ import ( func TestToInt(t *testing.T) { var eight interface{} = 8 assert.Equal(t, ToInt(8), 8) + assert.Equal(t, ToInt(8.31), 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 TestToString(t *testing.T) { + var foo interface{} = "one more time" + assert.Equal(t, ToString(8), "8") + assert.Equal(t, ToString(8.12), "8.12") + assert.Equal(t, ToString([]byte("one time")), "one time") + assert.Equal(t, ToString(foo), "one more time") + assert.Equal(t, ToString(nil), "") +} + 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 index 49025fc..80be149 100644 --- a/caste.go +++ b/caste.go @@ -53,58 +53,12 @@ func ToBoolE(i interface{}) (bool, bool) { 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 { @@ -141,12 +95,16 @@ func ToIntE(i interface{}) (int, bool) { jww.ERROR.Printf("Unable to Cast %#v to int", i) jww.ERROR.Println(err) } + case float64: + return int(s), true case bool: if bool(s) { return 1, true } else { return 0, true } + case nil: + return 0, true default: jww.ERROR.Printf("Unable to Cast %#v to int", i) } @@ -162,6 +120,8 @@ func ToStringE(i interface{}) (string, bool) { return strconv.FormatFloat(i.(float64), 'f', -1, 64), true case int: return strconv.FormatInt(int64(i.(int)), 10), true + case []byte: + return string(s), true case nil: return "", true default: @@ -171,6 +131,51 @@ func ToStringE(i interface{}) (string, bool) { return "", 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 StringToDate(s string) (time.Time, error) { return parseDateWith(s, []string{ time.RFC3339,