summaryrefslogtreecommitdiffhomepage
path: root/tpl
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <[email protected]>2019-11-21 21:59:38 +0100
committerBjørn Erik Pedersen <[email protected]>2019-11-22 18:41:50 +0100
commita3fe5e5e35f311f22b6b4fc38abfcf64cd2c7d6f (patch)
tree06cf1f647ae026b4fb3053c85370c2b203c7a089 /tpl
parentcd07e6d57b158a76f812e8c4c9567dbc84f57939 (diff)
downloadhugo-a3fe5e5e35f311f22b6b4fc38abfcf64cd2c7d6f.tar.gz
hugo-a3fe5e5e35f311f22b6b4fc38abfcf64cd2c7d6f.zip
Fix Params case handling in the index, sort and where func
This means that you can now do: ``` {{ range where .Site.Pages "Params.MYPARAM" "foo" }} ```
Diffstat (limited to 'tpl')
-rw-r--r--tpl/collections/collections_test.go11
-rw-r--r--tpl/collections/index.go10
-rw-r--r--tpl/collections/index_test.go5
-rw-r--r--tpl/collections/sort.go23
-rw-r--r--tpl/collections/sort_test.go16
-rw-r--r--tpl/collections/where.go22
-rw-r--r--tpl/collections/where_test.go49
-rw-r--r--tpl/resources/resources.go6
-rw-r--r--tpl/tplimpl/template_ast_transformers.go7
9 files changed, 132 insertions, 17 deletions
diff --git a/tpl/collections/collections_test.go b/tpl/collections/collections_test.go
index cfbcd312b..041a8e30c 100644
--- a/tpl/collections/collections_test.go
+++ b/tpl/collections/collections_test.go
@@ -22,6 +22,8 @@ import (
"testing"
"time"
+ "github.com/gohugoio/hugo/common/maps"
+
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/config"
@@ -891,6 +893,15 @@ type TstX struct {
unexported string
}
+type TstParams struct {
+ params maps.Params
+}
+
+func (x TstParams) Params() maps.Params {
+ return x.params
+
+}
+
type TstXIHolder struct {
XI TstXI
}
diff --git a/tpl/collections/index.go b/tpl/collections/index.go
index d2989e22f..cd1d1577b 100644
--- a/tpl/collections/index.go
+++ b/tpl/collections/index.go
@@ -17,6 +17,10 @@ import (
"errors"
"fmt"
"reflect"
+
+ "github.com/spf13/cast"
+
+ "github.com/gohugoio/hugo/common/maps"
)
// Index returns the result of indexing its first argument by the following
@@ -34,6 +38,11 @@ func (ns *Namespace) Index(item interface{}, args ...interface{}) (interface{},
return nil, errors.New("index of untyped nil")
}
+ lowerm, ok := item.(maps.Params)
+ if ok {
+ return lowerm.Get(cast.ToStringSlice(args)...), nil
+ }
+
var indices []interface{}
if len(args) == 1 {
@@ -79,6 +88,7 @@ func (ns *Namespace) Index(item interface{}, args ...interface{}) (interface{},
if err != nil {
return nil, err
}
+
if x := v.MapIndex(index); x.IsValid() {
v = x
} else {
diff --git a/tpl/collections/index_test.go b/tpl/collections/index_test.go
index c4cded47c..0c380d8d5 100644
--- a/tpl/collections/index_test.go
+++ b/tpl/collections/index_test.go
@@ -17,6 +17,8 @@ import (
"fmt"
"testing"
+ "github.com/gohugoio/hugo/common/maps"
+
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/deps"
)
@@ -42,7 +44,8 @@ func TestIndex(t *testing.T) {
{[]map[string]map[string]string{{"a": {"b": "c"}}}, []interface{}{0, "a", "b"}, "c", false},
{map[string]map[string]interface{}{"a": {"b": []string{"c", "d"}}}, []interface{}{"a", "b", 1}, "d", false},
{map[string]map[string]string{"a": {"b": "c"}}, []interface{}{[]string{"a", "b"}}, "c", false},
-
+ {maps.Params{"a": "av"}, []interface{}{"A"}, "av", false},
+ {maps.Params{"a": map[string]interface{}{"b": "bv"}}, []interface{}{"A", "B"}, "bv", false},
// errors
{nil, nil, nil, true},
{[]int{0, 1}, []interface{}{"1"}, nil, true},
diff --git a/tpl/collections/sort.go b/tpl/collections/sort.go
index 9639fe1d0..7ca764e9b 100644
--- a/tpl/collections/sort.go
+++ b/tpl/collections/sort.go
@@ -19,6 +19,7 @@ import (
"sort"
"strings"
+ "github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/tpl/compare"
"github.com/spf13/cast"
)
@@ -75,11 +76,19 @@ func (ns *Namespace) Sort(seq interface{}, args ...interface{}) (interface{}, er
} else {
v := p.Pairs[i].Value
var err error
- for _, elemName := range path {
+ for i, elemName := range path {
v, err = evaluateSubElem(v, elemName)
if err != nil {
return nil, err
}
+ if !v.IsValid() {
+ continue
+ }
+ // Special handling of lower cased maps.
+ if params, ok := v.Interface().(maps.Params); ok {
+ v = reflect.ValueOf(params.Get(path[i+1:]...))
+ break
+ }
}
p.Pairs[i].Key = v
}
@@ -89,6 +98,7 @@ func (ns *Namespace) Sort(seq interface{}, args ...interface{}) (interface{}, er
keys := seqv.MapKeys()
for i := 0; i < seqv.Len(); i++ {
p.Pairs[i].Value = seqv.MapIndex(keys[i])
+
if sortByField == "" {
p.Pairs[i].Key = keys[i]
} else if sortByField == "value" {
@@ -96,11 +106,19 @@ func (ns *Namespace) Sort(seq interface{}, args ...interface{}) (interface{}, er
} else {
v := p.Pairs[i].Value
var err error
- for _, elemName := range path {
+ for i, elemName := range path {
v, err = evaluateSubElem(v, elemName)
if err != nil {
return nil, err
}
+ if !v.IsValid() {
+ continue
+ }
+ // Special handling of lower cased maps.
+ if params, ok := v.Interface().(maps.Params); ok {
+ v = reflect.ValueOf(params.Get(path[i+1:]...))
+ break
+ }
}
p.Pairs[i].Key = v
}
@@ -135,6 +153,7 @@ func (p pairList) Less(i, j int) bool {
// can only call Interface() on valid reflect Values
return sortComp.Lt(iv.Interface(), jv.Interface())
}
+
// if j is invalid, test i against i's zero value
return sortComp.Lt(iv.Interface(), reflect.Zero(iv.Type()))
}
diff --git a/tpl/collections/sort_test.go b/tpl/collections/sort_test.go
index 612a928cb..2bf6e85fe 100644
--- a/tpl/collections/sort_test.go
+++ b/tpl/collections/sort_test.go
@@ -18,6 +18,8 @@ import (
"reflect"
"testing"
+ "github.com/gohugoio/hugo/common/maps"
+
"github.com/gohugoio/hugo/deps"
)
@@ -100,6 +102,20 @@ func TestSort(t *testing.T) {
"asc",
[]*TstX{{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"}, {A: "g", B: "h"}, {A: "i", B: "j"}},
},
+ // Lower case Params, slice
+ {
+ []TstParams{{params: maps.Params{"color": "indigo"}}, {params: maps.Params{"color": "blue"}}, {params: maps.Params{"color": "green"}}},
+ ".Params.COLOR",
+ "asc",
+ []TstParams{{params: maps.Params{"color": "blue"}}, {params: maps.Params{"color": "green"}}, {params: maps.Params{"color": "indigo"}}},
+ },
+ // Lower case Params, map
+ {
+ map[string]TstParams{"1": {params: maps.Params{"color": "indigo"}}, "2": {params: maps.Params{"color": "blue"}}, "3": {params: maps.Params{"color": "green"}}},
+ ".Params.CoLoR",
+ "asc",
+ []TstParams{{params: maps.Params{"color": "blue"}}, {params: maps.Params{"color": "green"}}, {params: maps.Params{"color": "indigo"}}},
+ },
// test map sorting by struct's method
{
map[string]TstX{"1": {A: "i", B: "j"}, "2": {A: "e", B: "f"}, "3": {A: "c", B: "d"}, "4": {A: "g", B: "h"}, "5": {A: "a", B: "b"}},
diff --git a/tpl/collections/where.go b/tpl/collections/where.go
index 42f0d370f..cada675f3 100644
--- a/tpl/collections/where.go
+++ b/tpl/collections/where.go
@@ -18,6 +18,8 @@ import (
"fmt"
"reflect"
"strings"
+
+ "github.com/gohugoio/hugo/common/maps"
)
// Where returns a filtered subset of a given data type.
@@ -277,6 +279,7 @@ func evaluateSubElem(obj reflect.Value, elemName string) (reflect.Value, error)
if !obj.IsValid() {
return zero, errors.New("can't evaluate an invalid value")
}
+
typ := obj.Type()
obj, isNil := indirect(obj)
@@ -295,6 +298,7 @@ func evaluateSubElem(obj reflect.Value, elemName string) (reflect.Value, error)
if objPtr.Kind() != reflect.Interface && objPtr.CanAddr() {
objPtr = objPtr.Addr()
}
+
mt, ok := objPtr.Type().MethodByName(elemName)
if ok {
switch {
@@ -368,16 +372,22 @@ func parseWhereArgs(args ...interface{}) (mv reflect.Value, op string, err error
// Array or Slice.
func (ns *Namespace) checkWhereArray(seqv, kv, mv reflect.Value, path []string, op string) (interface{}, error) {
rv := reflect.MakeSlice(seqv.Type(), 0, 0)
+
for i := 0; i < seqv.Len(); i++ {
var vvv reflect.Value
rvv := seqv.Index(i)
+
if kv.Kind() == reflect.String {
- vvv = rvv
- for _, elemName := range path {
- var err error
- vvv, err = evaluateSubElem(vvv, elemName)
- if err != nil {
- continue
+ if params, ok := rvv.Interface().(maps.Params); ok {
+ vvv = reflect.ValueOf(params.Get(path...))
+ } else {
+ vvv = rvv
+ for _, elemName := range path {
+ var err error
+ vvv, err = evaluateSubElem(vvv, elemName)
+ if err != nil {
+ continue
+ }
}
}
} else {
diff --git a/tpl/collections/where_test.go b/tpl/collections/where_test.go
index cdef7aefb..d6a1dd141 100644
--- a/tpl/collections/where_test.go
+++ b/tpl/collections/where_test.go
@@ -16,9 +16,12 @@ package collections
import (
"fmt"
"reflect"
+ "strings"
"testing"
"time"
+ "github.com/gohugoio/hugo/common/maps"
+
"github.com/gohugoio/hugo/deps"
)
@@ -163,6 +166,37 @@ func TestWhere(t *testing.T) {
},
},
{
+ seq: []maps.Params{
+ {"a": "a1", "b": "b1"}, {"a": "a2", "b": "b2"},
+ },
+ key: "B", match: "b2",
+ expect: []maps.Params{
+ maps.Params{"a": "a2", "b": "b2"},
+ },
+ },
+ {
+ seq: []maps.Params{
+ maps.Params{
+ "a": map[string]interface{}{
+ "b": "b1",
+ },
+ },
+ maps.Params{
+ "a": map[string]interface{}{
+ "b": "b2",
+ },
+ },
+ },
+ key: "A.B", match: "b2",
+ expect: []maps.Params{
+ maps.Params{
+ "a": map[string]interface{}{
+ "b": "b2",
+ },
+ },
+ },
+ },
+ {
seq: []*TstX{
{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
},
@@ -557,11 +591,24 @@ func TestWhere(t *testing.T) {
"zap": []interface{}{map[interface{}]interface{}{"a": 5, "b": 6}},
},
},
+ {
+ seq: map[string]interface{}{
+ "foo": []interface{}{maps.Params{"a": 1, "b": 2}},
+ "bar": []interface{}{maps.Params{"a": 3, "b": 4}},
+ "zap": []interface{}{maps.Params{"a": 5, "b": 6}},
+ },
+ key: "B", op: ">", match: 3,
+ expect: map[string]interface{}{
+ "bar": []interface{}{maps.Params{"a": 3, "b": 4}},
+ "zap": []interface{}{maps.Params{"a": 5, "b": 6}},
+ },
+ },
} {
testVariants := createTestVariants(test)
for j, test := range testVariants {
- name := fmt.Sprintf("[%d/%d] %T %s %s", i, j, test.seq, test.op, test.key)
+ name := fmt.Sprintf("%d/%d %T %s %s", i, j, test.seq, test.op, test.key)
+ name = strings.ReplaceAll(name, "[]", "slice-of-")
t.Run(name, func(t *testing.T) {
var results interface{}
var err error
diff --git a/tpl/resources/resources.go b/tpl/resources/resources.go
index e676a3412..20c4d1b3a 100644
--- a/tpl/resources/resources.go
+++ b/tpl/resources/resources.go
@@ -19,11 +19,11 @@ import (
"fmt"
"path/filepath"
- _errors "github.com/pkg/errors"
-
+ "github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/deps"
"github.com/gohugoio/hugo/resources"
"github.com/gohugoio/hugo/resources/resource"
+ _errors "github.com/pkg/errors"
"github.com/gohugoio/hugo/resources/resource_factories/bundler"
"github.com/gohugoio/hugo/resources/resource_factories/create"
@@ -301,7 +301,7 @@ func (ns *Namespace) resolveArgs(args []interface{}) (resources.ResourceTransfor
return nil, nil, fmt.Errorf("type %T not supported in Resource transformations", args[0])
}
- m, err := cast.ToStringMapE(args[0])
+ m, err := maps.ToStringMapE(args[0])
if err != nil {
return nil, nil, _errors.Wrap(err, "invalid options type")
}
diff --git a/tpl/tplimpl/template_ast_transformers.go b/tpl/tplimpl/template_ast_transformers.go
index d257d7a31..e25e70e35 100644
--- a/tpl/tplimpl/template_ast_transformers.go
+++ b/tpl/tplimpl/template_ast_transformers.go
@@ -19,11 +19,10 @@ import (
texttemplate "text/template"
"text/template/parse"
- "github.com/pkg/errors"
-
+ "github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/tpl"
"github.com/mitchellh/mapstructure"
- "github.com/spf13/cast"
+ "github.com/pkg/errors"
)
// decl keeps track of the variable mappings, i.e. $mysite => .Site etc.
@@ -315,7 +314,7 @@ func (c *templateContext) collectConfig(n *parse.PipeNode) {
if s, ok := cmd.Args[0].(*parse.StringNode); ok {
errMsg := "failed to decode $_hugo_config in template"
- m, err := cast.ToStringMapE(s.Text)
+ m, err := maps.ToStringMapE(s.Text)
if err != nil {
c.err = errors.Wrap(err, errMsg)
return