Skip to content

Commit

Permalink
Cleanup map conversion (#9)
Browse files Browse the repository at this point in the history
Current impl support maps with any value type (not only string or interface{}).
Implemantation can be cleaned up more by using simple type switch,
though, will be suitable only for yaml unmarshalling results.
  • Loading branch information
palestamp authored and mguzelevich committed Aug 6, 2018
1 parent 8ba4a14 commit 9f6e555
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 54 deletions.
53 changes: 13 additions & 40 deletions deinterfacer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,28 @@ import (
"reflect"
)

// convert `map[interface{}]interface{}` to `map[string]interface{}`
func deinterfacer(data interface{}) (interface{}, error) {
// deinterfacer converts `map[interface{}]interface{}` to `map[string]interface{}` recursively.
func deinterfacer(data interface{}) interface{} {
value := reflect.ValueOf(data)
switch value.Kind() {
case reflect.Map:
result := make(map[string]interface{})
_, ok := data.(map[string]interface{})
if !ok {
_, ok := data.(map[interface{}]interface{})
if !ok {
//
} else {
for key, value := range data.(map[interface{}]interface{}) {
if v, err := deinterfacer(value); err != nil {
//
} else {
result[fmt.Sprintf("%s", key)] = v
}
}
}
} else {
for key, value := range data.(map[string]interface{}) {
if v, err := deinterfacer(value); err != nil {
//
} else {
result[fmt.Sprintf("%s", key)] = v
}
}
for _, k := range value.MapKeys() {
result[fmt.Sprintf("%v", k)] = deinterfacer(value.MapIndex(k).Interface())
}
return result, nil

return result
case reflect.Slice:
s := reflect.ValueOf(data)
result := make([]interface{}, s.Len())
for i := 0; i < s.Len(); i++ {
value := s.Index(i).Interface()
if v, err := deinterfacer(value); err != nil {
//
} else {
result[i] = v
}
result := make([]interface{}, value.Len())
for i := 0; i < value.Len(); i++ {
result[i] = deinterfacer(value.Index(i).Interface())
}
return result, nil
return result
default:
return data, nil
return data
}
return nil, nil
}

func deinterface(data map[string]interface{}) (map[string]interface{}, error) {
result, err := deinterfacer(data)
return result.(map[string]interface{}), err
func deinterface(data map[string]interface{}) map[string]interface{} {
return deinterfacer(data).(map[string]interface{})
}
73 changes: 63 additions & 10 deletions deinterfacer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ package junocfg
// https://golang.org/pkg/testing/

import (
//"bytes"
"encoding/json"
"reflect"
//"bytes"

"testing"
)

var deinterfacerTests = []struct {
in map[string]interface{}
out string
out map[string]interface{}
}{
{
map[string]interface{}{
in: map[string]interface{}{
"a": "a",
"b": []string{"b1", "b2", "b3", "b4"},
"c": map[interface{}]interface{}{
Expand All @@ -36,20 +38,71 @@ var deinterfacerTests = []struct {
"eb": "eb",
"ec": "ec",
},
"f": []int{1, 2, 3, 4},
},
out: map[string]interface{}{
"a": "a",
"b": []interface{}{"b1", "b2", "b3", "b4"},
"c": map[string]interface{}{
"ca": "ca",
"cb": []interface{}{
"cb1",
"cb2",
map[string]interface{}{
"cb3a": "cb3aa",
},
"cb4",
map[string]interface{}{
"cb5a": "cb5aa",
},
},
},
"d": "a",
"e": map[string]interface{}{
"ea": "ea",
"eb": "eb",
"ec": "ec",
},
"f": []interface{}{1, 2, 3, 4},
},
},
{in: nil, out: map[string]interface{}{}},
{in: map[string]interface{}{}, out: map[string]interface{}{}},
{
in: map[string]interface{}{
"key_0": map[int]int{
1: 1,
2: 3,
5: 8,
13: 21,
},
},
out: map[string]interface{}{
"key_0": map[string]interface{}{
"1": 1,
"2": 3,
"5": 8,
"13": 21,
},
},
`{"a":"a","b":["b1","b2","b3","b4"],"c":{"ca":"ca","cb":["cb1","cb2",{"cb3a":"cb3aa"},"cb4",{"cb5a":"cb5aa"}]},"d":"a","e":{"ea":"ea","eb":"eb","ec":"ec"}}`,
},
}

func Test_deinterfacer(t *testing.T) {
for i, tst := range deinterfacerTests {
out, err := deinterface(tst.in)
if err != nil {
t.Errorf("For %d deinterface error %v", i, err)
out := deinterface(tst.in)
if !reflect.DeepEqual(tst.out, out) {
t.Errorf("For %d \nexpected %#v \ngot %#v", i, tst.out, out)
}
outStr, err := json.Marshal(out)
if string(outStr) != tst.out {
t.Errorf("For %d expected %v got %v", i, tst.out, string(outStr))
}
}

func Test_deinterfacereMarshallable(t *testing.T) {
for i, tst := range deinterfacerTests {
out := deinterface(tst.in)
_, err := json.Marshal(out)
if err != nil {
t.Errorf("For %d got error while marshalling %s", i, err)
}
}
}
5 changes: 1 addition & 4 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ func Items2Map(items ItemArray) (map[string]interface{}, error) {
return nil, err
}
}
result, err := deinterface(dst)
if err != nil {
return nil, err
}
result := deinterface(dst)
return result, nil
}

0 comments on commit 9f6e555

Please sign in to comment.