structure: remove returning error, it should panic just like reflect

package
This commit is contained in:
Fatih Arslan 2014-07-27 23:38:29 +03:00
parent 68345fdc8f
commit afdeeccc8b
4 changed files with 47 additions and 59 deletions

View File

@ -31,10 +31,7 @@ s := &Server{
Convert to a `map[string]interface{}` Convert to a `map[string]interface{}`
```go ```go
m, err := structure.ToMap(s) m := structure.ToMap(s)
if err != nil {
panic(err)
}
// prints: map[string]interface {}{"Name":"Arslan", "ID":123456, "Enabled":true} // prints: map[string]interface {}{"Name":"Arslan", "ID":123456, "Enabled":true}
fmt.Printf("%#v", m) fmt.Printf("%#v", m)
@ -46,10 +43,7 @@ Convert to a `[]interface{}`. Slice values are **sorted** by default according
to the field names. to the field names.
```go ```go
m, err := structure.ToSlice(s) m := structure.ToSlice(s)
if err != nil {
panic(err)
}
// prints: []interface {}{true, 123456, "Arslan"} // prints: []interface {}{true, 123456, "Arslan"}
fmt.Printf("%#v", m) fmt.Printf("%#v", m)

View File

@ -2,19 +2,16 @@
package structure package structure
import ( import (
"errors"
"reflect" "reflect"
"sort" "sort"
) )
// ErrNotStruct is returned when the passed value is not a struct // ToMap converts the given s struct to a map[string]interface{}. The default
var ErrNotStruct = errors.New("not struct") // map key names are the struct fieldnames but this can be changed by defining
// a "structure" tag key if needed. Note that only exported fields of a struct
// ToMap converts a struct to a map[string]interface{}. The default map key // can be accessed, non exported fields will be neglected. It panics if s's
// string is the struct fieldname but this can be changed by defining a // kind is not struct.
// "structure" tag key if needed. Note that only exported fields of a struct func ToMap(s interface{}) map[string]interface{} {
// can be accessed, non exported fields will be neglected.
func ToMap(s interface{}) (map[string]interface{}, error) {
out := make(map[string]interface{}) out := make(map[string]interface{})
t := reflect.TypeOf(s) t := reflect.TypeOf(s)
@ -27,7 +24,7 @@ func ToMap(s interface{}) (map[string]interface{}, error) {
} }
if t.Kind() != reflect.Struct { if t.Kind() != reflect.Struct {
return nil, ErrNotStruct panic("not struct")
} }
for i := 0; i < t.NumField(); i++ { for i := 0; i < t.NumField(); i++ {
@ -48,17 +45,15 @@ func ToMap(s interface{}) (map[string]interface{}, error) {
out[name] = v.Field(i).Interface() out[name] = v.Field(i).Interface()
} }
return out, nil return out
} }
// ToSlice converts a struct's field values to a []interface{}. Values are // ToSlice converts the given s struct's field values to a []interface{}.
// inserted and sorted according to the field names. Note that only exported // Values are inserted and sorted according to the field names. Note that only
// fields of a struct can be accessed, non exported fields will be neglected. // exported fields of a struct can be accessed, non exported fields will be
func ToSlice(s interface{}) ([]interface{}, error) { // neglected. It panics if s's kind is not struct.
m, err := ToMap(s) func ToSlice(s interface{}) []interface{} {
if err != nil { m := ToMap(s)
return nil, err
}
keys := make([]string, len(m)) keys := make([]string, len(m))
count := 0 count := 0
@ -75,10 +70,26 @@ func ToSlice(s interface{}) ([]interface{}, error) {
t[i] = m[key] t[i] = m[key]
} }
return t, nil return t
} }
// Fields returns a sorted slice of field names.
func Fields(s interface{}) []string {
m := ToMap(s)
keys := make([]string, len(m))
count := 0
for k := range m {
keys[count] = k
count++
}
sort.Strings(keys)
return keys
}
// IsStruct returns true if the given variable is a struct or a pointer to // IsStruct returns true if the given variable is a struct or a pointer to
// struct. // struct.
func IsStruct(s interface{}) bool { func IsStruct(s interface{}) bool {

View File

@ -15,10 +15,7 @@ func ExampleToMap() {
Enabled: true, Enabled: true,
} }
m, err := ToMap(s) m := ToMap(s)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", m["Name"]) fmt.Printf("%#v\n", m["Name"])
fmt.Printf("%#v\n", m["ID"]) fmt.Printf("%#v\n", m["ID"])
@ -43,10 +40,7 @@ func ExampleToMap_tags() {
ID: 789012, ID: 789012,
} }
m, err := ToMap(s) m := ToMap(s)
if err != nil {
panic(err)
}
// access them by the custom tags defined above // access them by the custom tags defined above
fmt.Printf("%#v\n", m["server_name"]) fmt.Printf("%#v\n", m["server_name"])
@ -72,10 +66,7 @@ func ExampleToSlice() {
Enabled: false, Enabled: false,
} }
m, err := ToSlice(s) m := ToSlice(s)
if err != nil {
panic(err)
}
// note that the output is sorted according to the field names // note that the output is sorted according to the field names
fmt.Printf("%#v\n", m) fmt.Printf("%#v\n", m)

View File

@ -8,11 +8,15 @@ import (
func TestToMapNonStruct(t *testing.T) { func TestToMapNonStruct(t *testing.T) {
foo := []string{"foo"} foo := []string{"foo"}
_, err := ToMap(foo) defer func() {
if err == nil { err := recover()
t.Error("ToMap shouldn't accept non struct types") if err == nil {
} t.Error("Passing a non struct into ToMap should panic")
}
}()
// this should panic. We are going to recover and and test it
_ = ToMap(foo)
} }
func TestToMap(t *testing.T) { func TestToMap(t *testing.T) {
@ -26,10 +30,7 @@ func TestToMap(t *testing.T) {
C: true, C: true,
} }
a, err := ToMap(T) a := ToMap(T)
if err != nil {
t.Error(err)
}
if typ := reflect.TypeOf(a).Kind(); typ != reflect.Map { if typ := reflect.TypeOf(a).Kind(); typ != reflect.Map {
t.Errorf("ToMap should return a map type, got: %v", typ) t.Errorf("ToMap should return a map type, got: %v", typ)
@ -69,19 +70,14 @@ func TestToMap_Tag(t *testing.T) {
C: true, C: true,
} }
a, err := ToMap(T) a := ToMap(T)
if err != nil {
t.Error(err)
}
inMap := func(key interface{}) bool { inMap := func(key interface{}) bool {
for k := range a { for k := range a {
if reflect.DeepEqual(k, key) { if reflect.DeepEqual(k, key) {
return true return true
} }
} }
return false return false
} }
@ -117,10 +113,7 @@ func TestToSlice(t *testing.T) {
C: true, C: true,
} }
s, err := ToSlice(T) s := ToSlice(T)
if err != nil {
t.Error(err)
}
inSlice := func(val interface{}) bool { inSlice := func(val interface{}) bool {
for _, v := range s { for _, v := range s {
@ -128,7 +121,6 @@ func TestToSlice(t *testing.T) {
return true return true
} }
} }
return false return false
} }