Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/gohugoio/hugo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/tpl
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2019-11-11 16:37:37 +0300
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2019-11-11 23:55:16 +0300
commita2670bf460e10ed5de69f90abbe7c4e2b32068cf (patch)
tree3af0c55190257a9db49b91f5068429de03972e72 /tpl
parent1a36ce9b0903e02a5068aed5f807ed9d21f48ece (diff)
tpl/collections: Allow dict to create nested structures
Fixes #6497
Diffstat (limited to 'tpl')
-rw-r--r--tpl/collections/collections.go29
-rw-r--r--tpl/collections/collections_test.go31
2 files changed, 43 insertions, 17 deletions
diff --git a/tpl/collections/collections.go b/tpl/collections/collections.go
index 0f0fd7ffb..8d89d6255 100644
--- a/tpl/collections/collections.go
+++ b/tpl/collections/collections.go
@@ -145,22 +145,41 @@ func (ns *Namespace) Delimit(seq, delimiter interface{}, last ...interface{}) (t
// Dictionary creates a map[string]interface{} from the given parameters by
// walking the parameters and treating them as key-value pairs. The number
// of parameters must be even.
+// The keys can be string slices, which will create the needed nested structure.
func (ns *Namespace) Dictionary(values ...interface{}) (map[string]interface{}, error) {
if len(values)%2 != 0 {
return nil, errors.New("invalid dictionary call")
}
- dict := make(map[string]interface{}, len(values)/2)
+ root := make(map[string]interface{})
for i := 0; i < len(values); i += 2 {
- key, ok := values[i].(string)
- if !ok {
- return nil, errors.New("dictionary keys must be strings")
+ dict := root
+ var key string
+ switch v := values[i].(type) {
+ case string:
+ key = v
+ case []string:
+ for i := 0; i < len(v)-1; i++ {
+ key = v[i]
+ var m map[string]interface{}
+ v, found := dict[key]
+ if found {
+ m = v.(map[string]interface{})
+ } else {
+ m = make(map[string]interface{})
+ dict[key] = m
+ }
+ dict = m
+ }
+ key = v[len(v)-1]
+ default:
+ return nil, errors.New("invalid dictionary key")
}
dict[key] = values[i+1]
}
- return dict, nil
+ return root, nil
}
// EchoParam returns a given value if it is set; otherwise, it returns an
diff --git a/tpl/collections/collections_test.go b/tpl/collections/collections_test.go
index 3830a7505..cfbcd312b 100644
--- a/tpl/collections/collections_test.go
+++ b/tpl/collections/collections_test.go
@@ -182,7 +182,6 @@ func TestDelimit(t *testing.T) {
}
func TestDictionary(t *testing.T) {
- t.Parallel()
c := qt.New(t)
ns := New(&deps.Deps{})
@@ -192,22 +191,30 @@ func TestDictionary(t *testing.T) {
expect interface{}
}{
{[]interface{}{"a", "b"}, map[string]interface{}{"a": "b"}},
+ {[]interface{}{[]string{"a", "b"}, "c"}, map[string]interface{}{"a": map[string]interface{}{"b": "c"}}},
+ {[]interface{}{[]string{"a", "b"}, "c", []string{"a", "b2"}, "c2", "b", "c"},
+ map[string]interface{}{"a": map[string]interface{}{"b": "c", "b2": "c2"}, "b": "c"}},
{[]interface{}{"a", 12, "b", []int{4}}, map[string]interface{}{"a": 12, "b": []int{4}}},
// errors
{[]interface{}{5, "b"}, false},
{[]interface{}{"a", "b", "c"}, false},
} {
- errMsg := qt.Commentf("[%d] %v", i, test.values)
-
- result, err := ns.Dictionary(test.values...)
-
- if b, ok := test.expect.(bool); ok && !b {
- c.Assert(err, qt.Not(qt.IsNil), errMsg)
- continue
- }
-
- c.Assert(err, qt.IsNil, errMsg)
- c.Assert(result, qt.DeepEquals, test.expect, errMsg)
+ i := i
+ test := test
+ c.Run(fmt.Sprint(i), func(c *qt.C) {
+ c.Parallel()
+ errMsg := qt.Commentf("[%d] %v", i, test.values)
+
+ result, err := ns.Dictionary(test.values...)
+
+ if b, ok := test.expect.(bool); ok && !b {
+ c.Assert(err, qt.Not(qt.IsNil), errMsg)
+ return
+ }
+
+ c.Assert(err, qt.IsNil, errMsg)
+ c.Assert(result, qt.DeepEquals, test.expect, qt.Commentf(fmt.Sprint(result)))
+ })
}
}