From ad0b154a3c280024190fa1965f2d13d820f5e8d5 Mon Sep 17 00:00:00 2001 From: Charles Phillips Date: Wed, 2 Mar 2016 03:30:30 -0800 Subject: [PATCH] Decode(map[string]interface{}) --- decode.go | 46 +++++++++++++++++++++++++++++++++++++++++----- decode_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/decode.go b/decode.go index cef8c3a..7364ccc 100644 --- a/decode.go +++ b/decode.go @@ -89,13 +89,49 @@ import ( // Field map[string]string `properties:"myName"` func (p *Properties) Decode(x interface{}) error { t, v := reflect.TypeOf(x), reflect.ValueOf(x) - if t.Kind() != reflect.Ptr || v.Elem().Type().Kind() != reflect.Struct { - return fmt.Errorf("not a pointer to struct: %s", t) + + if isPtr(t) { + elemT := v.Elem().Type() + switch { + case isMap(elemT): + m, ok := x.(*map[string]interface{}) + if !ok { + return fmt.Errorf("map type not map[string]interface {}", elemT) + } + for _, key := range p.Keys() { + value, _ := p.Get(key) + setNestedKey(*m, key, value) + } + return nil + + case isStruct(elemT): + if err := dec(p, "", nil, nil, v); err != nil { + return err + } + return nil + } } - if err := dec(p, "", nil, nil, v); err != nil { - return err + + return fmt.Errorf("not a pointer to map or struct: %s", t) +} + +func setNestedKey(m map[string]interface{}, key string, value interface{}) { + if strings.Contains(key, ".") { + kk := strings.SplitN(key, ".", 2) + prefix, rest := kk[0], kk[1] + if _, ok := m[prefix]; !ok { + m[prefix] = map[string]interface{}{} + } + setNestedKey(m[prefix].(map[string]interface{}), rest, value) + } else { + if reflect.TypeOf(value).Kind() == reflect.String { + val := value.(string) + if strings.Contains(val, ";") { + value = split(val, ";") + } + } + m[key] = value } - return nil } func dec(p *Properties, key string, def *string, opts map[string]string, v reflect.Value) error { diff --git a/decode_test.go b/decode_test.go index 4115fbb..bd74f3b 100644 --- a/decode_test.go +++ b/decode_test.go @@ -273,6 +273,31 @@ func TestDecodeMap(t *testing.T) { testDecode(t, in, &X{}, out) } +func TestDecodeToStringMap(t *testing.T) { + type S struct { + A string + } + X := make(map[string]interface{}) + in := ` + A.foo=bar + A.bar=bang + B.foo=a;b;c + B.bar=1;2;3 + C.foo.one=1 + C.foo.two=2 + C.bar.three=3 + C.bar.four=4 + D.foo.a=bar + ` + out := &map[string]interface{}{ + "A": map[string]interface{}{"foo": "bar", "bar": "bang"}, + "B": map[string]interface{}{"foo": []string{"a", "b", "c"}, "bar": []string{"1", "2", "3"}}, + "C": map[string]interface{}{"foo": map[string]interface{}{"one": "1", "two": "2"}, "bar": map[string]interface{}{"three": "3", "four": "4"}}, + "D": map[string]interface{}{"foo": map[string]interface{}{"a": "bar"}}, + } + testDecode(t, in, &X, out) +} + func testDecode(t *testing.T, in string, v, out interface{}) { p, err := parse(in) if err != nil {