Skip to content

Commit

Permalink
Decode(map[string]interface{})
Browse files Browse the repository at this point in the history
  • Loading branch information
doublerebel committed Mar 6, 2016
1 parent 497d0af commit ad0b154
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 5 deletions.
46 changes: 41 additions & 5 deletions decode.go
Expand Up @@ -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 {
Expand Down
25 changes: 25 additions & 0 deletions decode_test.go
Expand Up @@ -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 {
Expand Down

0 comments on commit ad0b154

Please sign in to comment.