Added accessing deep keys by recursive hierarchical search

This commit is contained in:
Kiril Zvezdarov 2015-04-26 15:02:19 -04:00
parent 2578450e4a
commit c174e2427c

View file

@ -107,6 +107,10 @@ func (rce RemoteConfigError) Error() string {
// "endpoint": "https://localhost" // "endpoint": "https://localhost"
// } // }
type Viper struct { type Viper struct {
// Delimiter that separates a list of keys
// used to access a nested value in one go
keyDelim string
// A set of paths to look for the config file in // A set of paths to look for the config file in
configPaths []string configPaths []string
@ -134,6 +138,7 @@ type Viper struct {
// Returns an initialized Viper instance. // Returns an initialized Viper instance.
func New() *Viper { func New() *Viper {
v := new(Viper) v := new(Viper)
v.keyDelim = "."
v.configName = "config" v.configName = "config"
v.config = make(map[string]interface{}) v.config = make(map[string]interface{})
v.override = make(map[string]interface{}) v.override = make(map[string]interface{})
@ -307,6 +312,26 @@ func (v *Viper) providerPathExists(p *remoteProvider) bool {
return false return false
} }
func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} {
if len(path) == 0 {
return source
}
if next, ok := source[path[0]]; ok {
switch next.(type) {
case map[string]interface{}:
// Type assertion is safe here since it is only reached
// if the type of `next` is the same as the type being asserted
return v.searchMap(next.(map[string]interface{}), path[1:])
default:
return next
}
} else {
return nil
}
}
// Viper is essentially repository for configurations // Viper is essentially repository for configurations
// Get can retrieve any value given the key to use // Get can retrieve any value given the key to use
// Get has the behavior of returning the value associated with the first // Get has the behavior of returning the value associated with the first
@ -316,13 +341,21 @@ func (v *Viper) providerPathExists(p *remoteProvider) bool {
// Get returns an interface. For a specific value use one of the Get____ methods. // Get returns an interface. For a specific value use one of the Get____ methods.
func Get(key string) interface{} { return v.Get(key) } func Get(key string) interface{} { return v.Get(key) }
func (v *Viper) Get(key string) interface{} { func (v *Viper) Get(key string) interface{} {
key = strings.ToLower(key) path := strings.Split(key, v.keyDelim)
val := v.find(key)
val := v.find(strings.ToLower(key))
if val == nil { if val == nil {
source := v.find(path[0])
if source == nil {
return nil return nil
} }
if reflect.TypeOf(source).Kind() == reflect.Map {
val = v.searchMap(cast.ToStringMap(source), path[1:])
}
}
switch val.(type) { switch val.(type) {
case bool: case bool:
return cast.ToBool(val) return cast.ToBool(val)