diff --git a/mapping.go b/mapping.go index cae51ea..d9fa4e9 100644 --- a/mapping.go +++ b/mapping.go @@ -3,7 +3,9 @@ // It can be used for example to access and manipulate arbitrary nested YAML/JSON structures. package dig -import "fmt" +import ( + "time" +) // Mapping is a nested key-value map where the keys are strings and values are any. In Ruby it is called a Hash (with string keys), in YAML it's called a "mapping". type Mapping map[string]any @@ -99,6 +101,26 @@ func (m *Mapping) Dup() Mapping { var ns []int ns = append(ns, vt...) new[k] = ns + case []float32: + var ns []float32 + ns = append(ns, vt...) + new[k] = ns + case []float64: + var ns []float64 + ns = append(ns, vt...) + new[k] = ns + case []time.Time: + var ns []time.Time + ns = append(ns, vt...) + new[k] = ns + case []time.Duration: + var ns []time.Duration + ns = append(ns, vt...) + new[k] = ns + case []byte: + var ns []byte + ns = append(ns, vt...) + new[k] = ns case []bool: var ns []bool ns = append(ns, vt...) @@ -114,7 +136,7 @@ func (m *Mapping) Dup() Mapping { func cleanUpInterfaceArray(in []any) []any { result := make([]any, len(in)) for i, v := range in { - result[i] = cleanUpMapValue(v) + result[i] = cleanUpValue(v) } return result } @@ -123,21 +145,19 @@ func cleanUpInterfaceArray(in []any) []any { func cleanUpInterfaceMap(in map[string]any) Mapping { result := make(Mapping) for k, v := range in { - result[fmt.Sprintf("%v", k)] = cleanUpMapValue(v) + result[k] = cleanUpValue(v) } return result } // Cleans up the value in the map, recurses in case of arrays and maps -func cleanUpMapValue(v any) any { +func cleanUpValue(v any) any { switch v := v.(type) { case []any: return cleanUpInterfaceArray(v) case map[string]any: return cleanUpInterfaceMap(v) - case string, int, bool, nil: - return v default: - return fmt.Sprintf("%v", v) + return v } } diff --git a/mapping_test.go b/mapping_test.go index cb2288a..e907535 100644 --- a/mapping_test.go +++ b/mapping_test.go @@ -40,6 +40,19 @@ func TestDig(t *testing.T) { t.Run("non-existing key should return nil", func(t *testing.T) { mustBeNil(t, m.Dig("foo", "non-existing")) }) + + t.Run("int value", func(t *testing.T) { + m.DigMapping("foo")["int"] = 1 + mustEqual(t, 1, m.Dig("foo", "int")) + }) + t.Run("float value", func(t *testing.T) { + m.DigMapping("foo")["float"] = 0.5 + mustEqual(t, 0.5, m.Dig("foo", "float")) + }) + t.Run("bool value", func(t *testing.T) { + m.DigMapping("foo")["bool"] = true + mustEqual(t, true, m.Dig("foo", "bool")) + }) } func TestDigString(t *testing.T) { @@ -133,6 +146,15 @@ func TestUnmarshalYamlWithNil(t *testing.T) { mustBeNil(t, m.Dig("foo")) } +func TestUnmarshalYamlWithFloat(t *testing.T) { + data := []byte(`{"foo": 0.5}`) + var m dig.Mapping + mustBeNil(t, json.Unmarshal(data, &m)) + val, ok := m.Dig("foo").(float64) + mustEqual(t, true, ok) + mustEqual(t, 0.5, val) +} + func ExampleMapping_Dig() { h := dig.Mapping{ "greeting": dig.Mapping{