func Read(ymlFlashMap map[string]interface{}) (FlashMap, error) { flashMap := newFlashMap() ymlAreas := ymlFlashMap["areas"] if ymlAreas == nil { return flashMap, util.NewNewtError( "\"areas\" mapping missing from flash map definition") } areaMap := cast.ToStringMap(ymlAreas) for k, v := range areaMap { if _, ok := flashMap.Areas[k]; ok { return flashMap, flashAreaErr(k, "name conflict") } ymlArea := cast.ToStringMap(v) area, err := parseFlashArea(k, ymlArea) if err != nil { return flashMap, flashAreaErr(k, err.Error()) } flashMap.Areas[k] = area } flashMap.detectOverlaps() return flashMap, nil }
func TestFlatMap(t *testing.T) { var v interface{} var err error m := map[string]interface{}{ ".cat": "garfield", ".dog": "odie", ".friends.[0]": "John", ".turtle": "0", ".birdColors.cardinal": "red", ".birdColors.blueJay": "blue", ".57": int64(57), ".doesItWork": true, } f := NewFlatMap(m) assert.Equal(t, f.Contains("cat"), true) assert.Equal(t, f.Contains(".cat"), false) assert.Equal(t, f.Contains(".birdColors.cardinal"), false) f.Delete("birdColors") r := map[string]interface{}{ "cat": "garfield", "dog": "odie", "friends": []interface{}{"John"}, "turtle": "0", "57": int64(57), "doesItWork": true, } v, err = Expand(f.Map, "") assert.Equal(t, cast.ToStringMap(v), r) assert.Equal(t, err, nil) m2 := map[string]interface{}{ ".friends.[0]": "Odie", ".friends.[1]": "John", } f2 := NewFlatMap(m2) f.Merge(f2) r2 := map[string]interface{}{ "cat": "garfield", "dog": "odie", "friends": []interface{}{"Odie", "John"}, "turtle": "0", "57": int64(57), "doesItWork": true, } v, err = Expand(f.Map, "") // FIXME: Buggy because of array order issues assert.Equal(t, cast.ToStringMap(v), r2) assert.Equal(t, err, nil) }
// searchMap recursively searches for a value for path in source map. // Returns nil if not found. // Note: This assumes that the path entries and map keys are lower cased. func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} { if len(path) == 0 { return source } next, ok := source[path[0]] if ok { // Fast path if len(path) == 1 { return next } // Nested case switch next.(type) { case map[interface{}]interface{}: return v.searchMap(cast.ToStringMap(next), path[1:]) 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: // got a value but nested key expected, return "nil" for not found return nil } } return nil }
// flattenAndMergeMap recursively flattens the given map into a map[string]bool // of key paths (used as a set, easier to manipulate than a []string): // - each path is merged into a single key string, delimited with v.keyDelim (= ".") // - if a path is shadowed by an earlier value in the initial shadow map, // it is skipped. // The resulting set of paths is merged to the given shadow set at the same time. func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interface{}, prefix string) map[string]bool { if shadow != nil && prefix != "" && shadow[prefix] { // prefix is shadowed => nothing more to flatten return shadow } if shadow == nil { shadow = make(map[string]bool) } var m2 map[string]interface{} if prefix != "" { prefix += v.keyDelim } for k, val := range m { fullKey := prefix + k switch val.(type) { case map[string]interface{}: m2 = val.(map[string]interface{}) case map[interface{}]interface{}: m2 = cast.ToStringMap(val) default: // immediate value shadow[strings.ToLower(fullKey)] = true continue } // recursively merge to shadow map shadow = v.flattenAndMergeMap(shadow, m2, fullKey) } return shadow }
// mergeFlatMap merges the given maps, excluding values of the second map // shadowed by values from the first map. func (v *Viper) mergeFlatMap(shadow map[string]bool, mi interface{}) map[string]bool { // unify input map var m map[string]interface{} switch mi.(type) { case map[string]string, map[string]FlagValue: m = cast.ToStringMap(mi) default: return shadow } // scan keys outer: for k, _ := range m { path := strings.Split(k, v.keyDelim) // scan intermediate paths var parentKey string for i := 1; i < len(path); i++ { parentKey = strings.Join(path[0:i], v.keyDelim) if shadow[parentKey] { // path is shadowed, continue continue outer } } // add key shadow[strings.ToLower(k)] = true } return shadow }
func (p *Page) getRenderingConfig() *helpers.Blackfriday { p.renderingConfigInit.Do(func() { pageParam := p.GetParam("blackfriday") siteParam := viper.GetStringMap("blackfriday") combinedParam := siteParam if pageParam != nil { combinedParam = make(map[string]interface{}) for k, v := range siteParam { combinedParam[k] = v } pageConfig := cast.ToStringMap(pageParam) for key, value := range pageConfig { combinedParam[key] = value } } p.renderingConfig = helpers.NewBlackfriday() if err := mapstructure.Decode(combinedParam, p.renderingConfig); err != nil { jww.FATAL.Printf("Failed to get rendering config for %s:\n%s", p.BaseFileName(), err.Error()) } }) return p.renderingConfig }
// Get can retrieve any value given the key to use // Get returns an interface. For a specific value use one of the Get____ methods. func (c RawConfig) Get(key string) interface{} { path := strings.Split(key, keyDelim) val := c.find(strings.ToLower(key)) if val == nil { source := c.find(path[0]) if source == nil { return nil } if reflect.TypeOf(source).Kind() == reflect.Map { val = c.searchMap(cast.ToStringMap(source), path[1:]) } } switch val.(type) { case bool: return cast.ToBool(val) case string: return cast.ToString(val) case int64, int32, int16, int8, int: return cast.ToInt(val) case float64, float32: return cast.ToFloat64(val) case time.Time: return cast.ToTime(val) case time.Duration: return cast.ToDuration(val) case []string: return val } return val }
func TestDifferentFrontMatterVarTypes(t *testing.T) { page, _ := NewPage("test/file1.md") _, _ = page.ReadFrom(strings.NewReader(PAGE_WITH_VARIOUS_FRONTMATTER_TYPES)) dateval, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") if page.GetParam("a_string") != "bar" { t.Errorf("frontmatter not handling strings correctly should be %s, got: %s", "bar", page.GetParam("a_string")) } if page.GetParam("an_integer") != 1 { t.Errorf("frontmatter not handling ints correctly should be %s, got: %s", "1", page.GetParam("an_integer")) } if page.GetParam("a_float") != 1.3 { t.Errorf("frontmatter not handling floats correctly should be %f, got: %s", 1.3, page.GetParam("a_float")) } if page.GetParam("a_bool") != false { t.Errorf("frontmatter not handling bools correctly should be %t, got: %s", false, page.GetParam("a_bool")) } if page.GetParam("a_date") != dateval { t.Errorf("frontmatter not handling dates correctly should be %s, got: %s", dateval, page.GetParam("a_date")) } param := page.GetParam("a_table") if param == nil { t.Errorf("frontmatter not handling tables correctly should be type of %v, got: type of %v", reflect.TypeOf(page.Params["a_table"]), reflect.TypeOf(param)) } if cast.ToStringMap(param)["a_key"] != "a_value" { t.Errorf("frontmatter not handling values inside a table correctly should be %s, got: %s", "a_value", cast.ToStringMap(page.Params["a_table"])["a_key"]) } }
// NewBlackfriday creates a new Blackfriday filled with site config or some sane defaults. func NewBlackfriday() *Blackfriday { combinedParam := map[string]interface{}{ "smartypants": true, "angledQuotes": false, "fractions": true, "hrefTargetBlank": false, "smartDashes": true, "latexDashes": true, "plainIDAnchors": true, "sourceRelativeLinks": false, "sourceRelativeLinksProjectFolder": "/docs/content", } siteParam := viper.GetStringMap("blackfriday") if siteParam != nil { siteConfig := cast.ToStringMap(siteParam) for key, value := range siteConfig { combinedParam[key] = value } } combinedConfig := &Blackfriday{} if err := mapstructure.Decode(combinedParam, combinedConfig); err != nil { jww.FATAL.Printf("Failed to get site rendering config\n%s", err.Error()) } return combinedConfig }
func TestMapMap(t *testing.T) { var v interface{} var processingErrors []error var err error m := map[string]interface{}{ "cat": "garfield", "dog": "odie", "friends": []interface{}{"John"}, "turtle": "0", "57": int64(57), "doesItWork": true, } r := map[string]interface{}{ "cat": "garfield", "frog": "0", "myOnlyFriend": "John", } var mappers []*Mapper mappers = append(mappers, NewMapper("cat", "cat")) mappers = append(mappers, NewMapper("turtle", "frog")) mappers = append(mappers, NewMapper("friends.[0]", "myOnlyFriend")) v, processingErrors, err = MapIt(m, mappers) assert.Equal(t, cast.ToStringMap(v), r) assert.Equal(t, processingErrors, []error{}) assert.Equal(t, len(processingErrors), 0) assert.Equal(t, err, nil) }
func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} { if len(path) == 0 { return source } var ok bool var next interface{} for k, v := range source { if strings.ToLower(k) == strings.ToLower(path[0]) { ok = true next = v break } } if ok { switch next.(type) { case map[interface{}]interface{}: return v.searchMap(cast.ToStringMap(next), path[1:]) 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 } }
// Updates our lookup table of insensitive materialized paths to their // corresponding 'real' keys. E.g. // // Database.Connections.Hosts <- database.connections.hosts // // By maintaining a separate index and maintaining case in the original // stringmaps (e.g. by lowercasing keys directly) we accomodate the passing // of config data to structures that ~may~ be case sensitive. I.E we avoid // destructive operations on configurationd data. func (self *ConfigSource) updateIndex(key string, data interface{}) { if data == nil { return } // Don't change the case of the original key if it already exists. _, index_exists := self.index[strings.ToLower(key)] if index_exists == false { self.index[strings.ToLower(key)] = key } if reflect.TypeOf(data).Kind() != reflect.Map { return } for child_key, val := range cast.ToStringMap(data) { var joined_key string if len(key) > 0 { joined_key = key + "." + child_key } else { joined_key = child_key } self.updateIndex(joined_key, val) } }
// Merges data into the our attributes configuration tier from a struct. func (manager *Config) MergeAttributes(val interface{}) error { merged_config := maps.Merge( manager.attributes.ToStringMap(), cast.ToStringMap(val), ) manager.attributes.FromStringMap(merged_config) return nil }
func (v *Viper) Sub(key string) *Viper { subv := New() data := v.Get(key) if reflect.TypeOf(data).Kind() == reflect.Map { subv.config = cast.ToStringMap(data) return subv } return nil }
// toCaseInsensitiveValue checks if the value is a map; // if so, create a copy and lower-case the keys recursively. func toCaseInsensitiveValue(value interface{}) interface{} { switch v := value.(type) { case map[interface{}]interface{}: value = copyAndInsensitiviseMap(cast.ToStringMap(v)) case map[string]interface{}: value = copyAndInsensitiviseMap(v) } return value }
func (p *Page) getRenderingConfig() *helpers.Blackfriday { p.renderingConfigInit.Do(func() { pageParam := cast.ToStringMap(p.GetParam("blackfriday")) p.renderingConfig = helpers.NewBlackfriday() if err := mapstructure.Decode(pageParam, p.renderingConfig); err != nil { jww.FATAL.Printf("Failed to get rendering config for %s:\n%s", p.BaseFileName(), err.Error()) } }) return p.renderingConfig }
func insensitiviseMap(m map[string]interface{}) { for key, val := range m { lower := strings.ToLower(key) if key != lower { delete(m, key) m[lower] = val } if val != nil && reflect.TypeOf(val).Kind() == reflect.Map { insensitiviseMap(cast.ToStringMap(val)) } } }
func (v *Viper) Get(key string) interface{} { path := strings.Split(key, v.keyDelim) var val interface{} lcaseKey := strings.ToLower(key) source := v.find(path[0]) if source != nil { if reflect.TypeOf(source).Kind() == reflect.Map { val = v.searchMap(cast.ToStringMap(source), path[1:]) } } if val == nil { val = v.find(lcaseKey) } if val == nil { return nil } var valType interface{} if !v.typeByDefValue { valType = val } else { defVal, defExists := v.defaults[lcaseKey] if defExists { valType = defVal } else { valType = val } } switch valType.(type) { case bool: return cast.ToBool(val) case string: return cast.ToString(val) case int64, int32, int16, int8, int: return cast.ToInt(val) case float64, float32: return cast.ToFloat64(val) case time.Time: return cast.ToTime(val) case time.Duration: return cast.ToDuration(val) case []string: return cast.ToStringSlice(val) } return val }
func (c *Configr) mergeMap(key string, value interface{}, targetMap map[string]interface{}) map[string]interface{} { if reflect.TypeOf(value).Kind() == reflect.Map { targetMap = c.traverseSubMap(key, cast.ToStringMap(value), targetMap) } else { path := strings.SplitN(key, c.keyDelimeter, 2) if len(path) == 2 { targetMap = c.traverseKeyPath(path[0], path[1], value, targetMap) } else { targetMap[key] = value } } return targetMap }
func GetStringMapFeatures(v *viper.Viper, features map[string]bool, key string) map[string]interface{} { result := map[string]interface{}{} slice := GetSliceFeatures(v, features, key) for _, itf := range slice { sub := cast.ToStringMap(itf) for k, v := range sub { result[k] = v } } return result }
// Generic functional, recursive stringmap traversal. // Provides the callback with the current value, materialized path, and depth. func traverse(data map[string]interface{}, path string, depth int, cb Traverser) { for key, val := range data { var joined_key string if len(path) > 0 { joined_key = path + "." + key } else { joined_key = key } if cb(joined_key, val, depth) { if val != nil && reflect.TypeOf(val).Kind() == reflect.Map { traverse(cast.ToStringMap(val), joined_key, depth+1, cb) } } } }
func (c *Configr) findKeysAndValuesToValidate(key string, value interface{}) (map[string]interface{}, error) { keysAndValues := make(map[string]interface{}) if reflect.TypeOf(value).Kind() == reflect.Map { for validatorKey := range c.valueValidators { if !strings.HasPrefix(validatorKey, key) { continue } valueToValidate := searchMap(cast.ToStringMap(value), strings.Split(validatorKey, c.keyDelimeter)[1:]) keysAndValues[validatorKey] = valueToValidate } } else { keysAndValues[key] = value } return keysAndValues, nil }
func (suite *GitConfigTestSuite) TestCast() { assert := assert.New(suite.T()) hostsRaw := viper.Get("git.hosts") //fmt.Println(hostsRaw) hostsSlice := cast.ToSlice(hostsRaw) //fmt.Println(hostsSlice) for _, host := range hostsSlice { hostMap := cast.ToStringMap(host) name := cast.ToString(hostMap["name"]) https := cast.ToBool(hostMap["https"]) if name == "git.saber.io" { assert.Equal(false, https) } } }
// copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of // any map it makes case insensitive. func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} { nm := make(map[string]interface{}) for key, val := range m { lkey := strings.ToLower(key) switch v := val.(type) { case map[interface{}]interface{}: nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v)) case map[string]interface{}: nm[lkey] = copyAndInsensitiviseMap(v) default: nm[lkey] = v } } return nm }
func (v *Viper) IsSet(key string) bool { path := strings.Split(key, v.keyDelim) lcaseKey := strings.ToLower(key) val := v.find(lcaseKey) if val == nil { source := v.find(strings.ToLower(path[0])) if source != nil { if reflect.TypeOf(source).Kind() == reflect.Map { val = v.searchMap(cast.ToStringMap(source), path[1:]) } } } return val != nil }
func (p *Page) getRenderingConfig() *helpers.Blackfriday { p.renderingConfigInit.Do(func() { pageParam := cast.ToStringMap(p.GetParam("blackfriday")) if p.Language() == nil { panic(fmt.Sprintf("nil language for %s with source lang %s", p.BaseFileName(), p.lang)) } p.renderingConfig = helpers.NewBlackfriday(p.Language()) if err := mapstructure.Decode(pageParam, p.renderingConfig); err != nil { jww.FATAL.Printf("Failed to get rendering config for %s:\n%s", p.BaseFileName(), err.Error()) } }) return p.renderingConfig }
func (c *Config) expandKeysValues(vd map[string]interface{}, kkl string) { defMap := make(map[string]interface{}) kl := "" for k, v := range vd { if kkl != "" { kl = kkl + "." + k } else { kl = k } if reflect.TypeOf(v) == reflect.TypeOf(defMap) { c.expandKeysValues(cast.ToStringMap(v), kl) } else { var val interface{} = v c.configValues[kl] = val } } }
// Loads and sequentially + recursively merges the provided config arguments. Returns // an error if any of the files fail to load, though this may be expecte // in the case of search paths. func (manager *Config) ReadPaths(paths ...string) error { var err error var loaded interface{} merged_config := manager.attributes.ToStringMap() errs := []error{} for _, base_path := range paths { var final_path string if filepath.IsAbs(base_path) == false { final_path = path.Join(manager.rootPath, base_path) } else { final_path = path.Join(manager.rootPath, base_path) } loaded, err = reader.ReadFile(final_path) if err != nil { errs = append(errs, err) continue } // In-place recursive coercion to stringmap. coerced := cast.ToStringMap(loaded) maps.ToStringMapRecursive(coerced) if merged_config == nil { merged_config = coerced } else { merged_config = maps.Merge( merged_config, coerced, ) } manager.attributes.FromStringMap(merged_config) } if len(errs) > 0 { return &errors.LoadError{Errors: errs} } else { return nil } }
func (c *Config) searchMap(s map[string]interface{}, p []string) interface{} { if len(p) == 0 { return s } if next, ok := s[p[0]]; ok { switch next.(type) { case map[interface{}]interface{}: return c.searchMap(cast.ToStringMap(next), p[1:]) case map[string]interface{}: return c.searchMap(next.(map[string]interface{}), p[1:]) default: return next } } else { return nil } }
// ToLowerMap makes all the keys in the given map lower cased and will do so // recursively. // Notes: // * This will modify the map given. // * Any nested map[interface{}]interface{} will be converted to map[string]interface{}. func ToLowerMap(m map[string]interface{}) { for k, v := range m { switch v.(type) { case map[interface{}]interface{}: v = cast.ToStringMap(v) ToLowerMap(v.(map[string]interface{})) case map[string]interface{}: ToLowerMap(v.(map[string]interface{})) } lKey := strings.ToLower(k) if k != lKey { delete(m, k) m[lKey] = v } } }