From 02eb49d4bd5b77fd92f01edbe3dad7c0603ea743 Mon Sep 17 00:00:00 2001 From: Herkermer Sherwood Date: Sat, 29 Apr 2017 14:27:45 -0700 Subject: [PATCH 1/4] Fix small lint issues --- viper.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/viper.go b/viper.go index 31b41a6..5377ddc 100644 --- a/viper.go +++ b/viper.go @@ -53,7 +53,7 @@ func init() { type remoteConfigFactory interface { Get(rp RemoteProvider) (io.Reader, error) Watch(rp RemoteProvider) (io.Reader, error) - WatchChannel(rp RemoteProvider)(<-chan *RemoteResponse, chan bool) + WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool) } // RemoteConfig is optional, see the remote package @@ -746,7 +746,7 @@ func (v *Viper) Unmarshal(rawVal interface{}) error { return nil } -// defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot +// defaultDecoderConfig returns default mapsstructure.DecoderConfig with support // of time.Duration values func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig { return &mapstructure.DecoderConfig{ From c254a5ba545ed40ffe93e8a2a1d6a09a3c2c60cc Mon Sep 17 00:00:00 2001 From: Herkermer Sherwood Date: Sat, 29 Apr 2017 14:28:30 -0700 Subject: [PATCH 2/4] Add parallel functions/methods to unmarshal data and return mapstructure.Metadata This was not added for UnmarshalExact, since all keys should be used and none left unused. --- viper.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/viper.go b/viper.go index 5377ddc..ac98754 100644 --- a/viper.go +++ b/viper.go @@ -731,6 +731,27 @@ func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error { return nil } +// UnmarshalKeyWithMeta performs UnmarshalKey and using an additional +// parameter, also provides access to the mapstructure.Metadata. +func UnmarshalKeyWithMeta(key string, rawVal interface{}) (mapstructure.Metadata, error) { + return v.UnmarshalKeyWithMeta(key, rawVal) +} +func (v *Viper) UnmarshalKeyWithMeta(key string, rawVal interface{}) (mapstructure.Metadata, error) { + var meta mapstructure.Metadata + config := defaultDecoderConfig(rawVal) + config.Metadata = &meta + + err := decode(v.Get(key), config) + + if err != nil { + return meta, err + } + + v.insensitiviseMaps() + + return meta, nil +} + // Unmarshal unmarshals the config into a Struct. Make sure that the tags // on the fields of the structure are properly set. func Unmarshal(rawVal interface{}) error { return v.Unmarshal(rawVal) } @@ -746,6 +767,27 @@ func (v *Viper) Unmarshal(rawVal interface{}) error { return nil } +// UnmarshalWithMeta performs Unmarshal and using an additional +// parameter, also provides access to the mapstructure.Metadata. +func UnmarshalWithMeta(rawVal interface{}) (mapstructure.Metadata, error) { + return v.UnmarshalWithMeta(rawVal) +} +func (v *Viper) UnmarshalWithMeta(rawVal interface{}) (mapstructure.Metadata, error) { + var meta mapstructure.Metadata + config := defaultDecoderConfig(rawVal) + config.Metadata = &meta + + err := decode(v.AllSettings(), config) + + if err != nil { + return meta, err + } + + v.insensitiviseMaps() + + return meta, nil +} + // defaultDecoderConfig returns default mapsstructure.DecoderConfig with support // of time.Duration values func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig { From ed787f03db37a9f52cb1ac6123f8feae3db1b1ea Mon Sep 17 00:00:00 2001 From: Herkermer Sherwood Date: Sat, 29 Apr 2017 14:30:24 -0700 Subject: [PATCH 3/4] Add a tests and examples for each new method --- viper_test.go | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/viper_test.go b/viper_test.go index 774ca11..fdfeea9 100644 --- a/viper_test.go +++ b/viper_test.go @@ -275,6 +275,85 @@ func TestUnmarshalling(t *testing.T) { assert.Equal(t, 35, Get("age")) } +func ExampleUnmarshalWithMeta() { + v := New() + type Lib struct { + Name string + Awesome bool + Useful bool + } + var libsCfg struct { + Libs map[string]Lib + } + v.config = map[string]interface{}{ + "libs": map[string]interface{}{ + "viper": map[string]interface{}{ + "name": "Viper", + "awesome": true, + "tagline": "Go configuration with fangs!", + }, + }, + "numbers": []int{4, 8, 15, 16, 23, 42}, + } + meta, _ := v.UnmarshalWithMeta(&libsCfg) + // The keys slice is not stable. Sorting them in lexicographical + // order allows comparison. + sort.Strings(meta.Keys) + sort.Strings(meta.Unused) + fmt.Printf("%#v\n", meta.Keys) + fmt.Printf("%#v", meta.Unused) + // Output: + // []string{"Libs", "Libs[viper]", "Libs[viper]", "Libs[viper].Awesome", "Libs[viper].Name"} + // []string{"Libs[viper].tagline", "numbers"} +} + +func ExampleUnmarshalKeyWithMeta() { + v := New() + var lib struct { + Name string + Awesome bool + Useful bool + } + v.config = map[string]interface{}{ + "libs": map[string]interface{}{ + "viper": map[string]interface{}{ + "name": "Viper", + "awesome": true, + "tagline": "Go configuration with fangs!", + }, + }, + } + meta, _ := v.UnmarshalKeyWithMeta("libs.viper", &lib) + fmt.Println(meta.Keys) + fmt.Println(meta.Unused) + // Output: + // [Name Awesome] + // [tagline] +} + +func TestUnmarshalKeyWithMeta(t *testing.T) { + v := New() + v.SetConfigType("yaml") + err := v.ReadConfig(bytes.NewBuffer(yamlExample)) + if err != nil { + t.Fatal(err) + } + var clothes struct { + Jacket string + Pants interface{} + } + meta, err := v.UnmarshalKeyWithMeta("clothing", &clothes) + if err != nil { + t.Fatal(err) + } + keys := []string{"Jacket", "Pants"} + unused := []string{"trousers"} + sort.Strings(meta.Keys) + sort.Strings(meta.Unused) + assert.Equal(t, keys, meta.Keys, "keys decoded") + assert.Equal(t, unused, meta.Unused, "keys in config not in struct") +} + func TestUnmarshalExact(t *testing.T) { vip := New() target := &testUnmarshalExtra{} From 103db871f33aa9bbfcd91de421d95175f758f5ae Mon Sep 17 00:00:00 2001 From: Herkermer Sherwood Date: Sat, 29 Apr 2017 14:36:07 -0700 Subject: [PATCH 4/4] Fix documentation to correctly reflect implementation --- viper.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/viper.go b/viper.go index ac98754..a5fa2ab 100644 --- a/viper.go +++ b/viper.go @@ -731,8 +731,8 @@ func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error { return nil } -// UnmarshalKeyWithMeta performs UnmarshalKey and using an additional -// parameter, also provides access to the mapstructure.Metadata. +// UnmarshalKeyWithMeta performs UnmarshalKey and provides access to the +// mapstructure.Metadata in an additional return value. func UnmarshalKeyWithMeta(key string, rawVal interface{}) (mapstructure.Metadata, error) { return v.UnmarshalKeyWithMeta(key, rawVal) } @@ -767,8 +767,8 @@ func (v *Viper) Unmarshal(rawVal interface{}) error { return nil } -// UnmarshalWithMeta performs Unmarshal and using an additional -// parameter, also provides access to the mapstructure.Metadata. +// UnmarshalWithMeta performs Unmarshal and provides access to the +// mapstructure.Metadata in an additional return value. func UnmarshalWithMeta(rawVal interface{}) (mapstructure.Metadata, error) { return v.UnmarshalWithMeta(rawVal) }