diff --git a/koanf.go b/koanf.go index 24505cc..9d12119 100644 --- a/koanf.go +++ b/koanf.go @@ -239,7 +239,9 @@ func (ko *Koanf) UnmarshalWithConf(path string, o interface{}, c UnmarshalConf) if c.DecoderConfig == nil { c.DecoderConfig = &mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( - mapstructure.StringToTimeDurationHookFunc()), + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + mapstructure.TextUnmarshallerHookFunc()), Metadata: nil, Result: o, WeaklyTypedInput: true, diff --git a/koanf_test.go b/koanf_test.go index 73788ac..18a46e0 100644 --- a/koanf_test.go +++ b/koanf_test.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" "regexp" + "strconv" "strings" "sync" "testing" @@ -245,6 +246,26 @@ type testStructFlat struct { Parent1Child1Grandchild1On bool `koanf:"parent1.child1.grandchild1.on"` } +type customText int + +func (c *customText) UnmarshalText(text []byte) error { + s := strings.ToLower(string(text)) + + switch { + case strings.HasSuffix(s, "mb"): + s = strings.TrimSuffix(s, "mb") + default: + s = "0" + } + + v, err := strconv.ParseFloat(s, 64) + if err != nil { + return err + } + *c = customText(v) + return nil +} + type Case struct { koanf *koanf.Koanf file string @@ -922,6 +943,27 @@ func TestUnmarshalFlat(t *testing.T) { } } +func TestUnmarshalCustomText(t *testing.T) { + test := struct { + V1 customText `koanf:"v1"` + V2 string `koanf:"v2"` + V3 customText `koanf:"v3"` + }{} + + // Test custom unmarshalling of strings via mapstructure's UnmarshalText() + // methods. customText is a int type that strips of the `mb` suffix and parses + // the rest into a number. + + k := koanf.New(delim) + err := k.Load(rawbytes.Provider([]byte(`{"v1": "42mb", "v2": "42mb"}`)), json.Parser()) + assert.NoError(t, err) + + k.Unmarshal("", &test) + assert.Equal(t, int(test.V1), 42) + assert.Equal(t, test.V2, "42mb") + assert.Equal(t, int(test.V3), 0) +} + func TestMarshal(t *testing.T) { assert := assert.New(t)