Support time.Duration in viper.Unmarshal (#205)
* Fixes #105
diff --git a/viper.go b/viper.go
index 8a32482..fafabde 100644
--- a/viper.go
+++ b/viper.go
@@ -624,7 +624,7 @@
// on the fields of the structure are properly set.
func Unmarshal(rawVal interface{}) error { return v.Unmarshal(rawVal) }
func (v *Viper) Unmarshal(rawVal interface{}) error {
- err := mapstructure.WeakDecode(v.AllSettings(), rawVal)
+ err := decode(v.AllSettings(), defaultDecoderConfig(rawVal))
if err != nil {
return err
@@ -635,16 +635,19 @@
return nil
}
-// A wrapper around mapstructure.Decode that mimics the WeakDecode functionality
-// while erroring on non existing vals in the destination struct.
-func weakDecodeExact(input, output interface{}) error {
- config := &mapstructure.DecoderConfig{
- ErrorUnused: true,
+// defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot
+// of time.Duration values
+func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig {
+ return &mapstructure.DecoderConfig{
Metadata: nil,
Result: output,
WeaklyTypedInput: true,
+ DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
}
+}
+// A wrapper around mapstructure.Decode that mimics the WeakDecode functionality
+func decode(input interface{}, config *mapstructure.DecoderConfig) error {
decoder, err := mapstructure.NewDecoder(config)
if err != nil {
return err
@@ -655,7 +658,10 @@
// UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent
// in the destination struct.
func (v *Viper) UnmarshalExact(rawVal interface{}) error {
- err := weakDecodeExact(v.AllSettings(), rawVal)
+ config := defaultDecoderConfig(rawVal)
+ config.ErrorUnused = true
+
+ err := decode(v.AllSettings(), config)
if err != nil {
return err
diff --git a/viper_test.go b/viper_test.go
index cf897d6..127e650 100644
--- a/viper_test.go
+++ b/viper_test.go
@@ -453,10 +453,12 @@
func TestUnmarshal(t *testing.T) {
SetDefault("port", 1313)
Set("name", "Steve")
+ Set("duration", "1s1ms")
type config struct {
- Port int
- Name string
+ Port int
+ Name string
+ Duration time.Duration
}
var C config
@@ -466,14 +468,14 @@
t.Fatalf("unable to decode into struct, %v", err)
}
- assert.Equal(t, &C, &config{Name: "Steve", Port: 1313})
+ assert.Equal(t, &C, &config{Name: "Steve", Port: 1313, Duration: time.Second + time.Millisecond})
Set("port", 1234)
err = Unmarshal(&C)
if err != nil {
t.Fatalf("unable to decode into struct, %v", err)
}
- assert.Equal(t, &C, &config{Name: "Steve", Port: 1234})
+ assert.Equal(t, &C, &config{Name: "Steve", Port: 1234, Duration: time.Second + time.Millisecond})
}
func TestBindPFlags(t *testing.T) {