ref: 09038865c24f420ac059a5cb8172da04c0391e58
parent: ffbd2b6c67fd92305e4fc3c2ee580f731bc24cc1
author: Christopher Mancini <[email protected]>
date: Mon Apr 11 12:58:27 EDT 2016
tpl: Add intersect operator to where function Returns true if a given field value that is a slice / array of strings, integers or floats contains elements in common with the matching value. It follows the same rules as the intersect function. Closes #1945
--- a/docs/content/templates/functions.md
+++ b/docs/content/templates/functions.md
@@ -67,7 +67,7 @@
Invalid combinations like keys that are not strings or uneven number of parameters, will result in an exception thrown.
Useful for passing maps to partials when adding to a template.
-e.g. Pass into "foo.html" a map with the keys "important, content"
+e.g. Pass into "foo.html" a map with the keys "important, content"
{{$important := .Site.Params.SomethingImportant }}
{{range .Site.Params.Bar}}
@@ -78,9 +78,8 @@
Important {{.important}}
{{.content}}
-
-or create a map on the fly to pass into
+or create a map on the fly to pass into
{{partial "foo" (dict "important" "Smiles" "content" "You should do more")}}
@@ -313,7 +312,16 @@
- `<`, `lt`: True if a given field value is lesser than a matching value
- `in`: True if a given field value is included in a matching value. A matching value must be an array or a slice
- `not in`: True if a given field value isn't included in a matching value. A matching value must be an array or a slice
+- `intersect`: True if a given field value that is a slice / array of strings or integers contains elements in common with the matching value. It follows the same rules as the intersect function.
+*`intersect` operator, e.g.:*
+
+ {{ range where .Site.Pages ".Params.tags" "intersect" .Params.tags }}
+ {{ if ne .Permalink $.Permalink }}
+ {{ .Render "summary" }}
+ {{ end }}
+ {{ end }}
+
*`where` and `first` can be stacked, e.g.:*
{{ range first 5 (where .Data.Pages "Section" "post") }}
@@ -340,7 +348,7 @@
### readDir
-Gets a directory listing from a directory relative to the current project working dir.
+Gets a directory listing from a directory relative to the current project working dir.
So, If the project working dir has a single file named `README.txt`:
@@ -349,7 +357,7 @@
### readFile
Reads a file from disk and converts it into a string. Note that the filename must be relative to the current project working dir.
So, if you have a file with the name `README.txt` in the root of your project with the content `Hugo Rocks!`:
-
+
`{{readFile "README.txt"}}` → `"Hugo Rocks!"`
## Math
--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -646,6 +646,7 @@
var ivp, imvp *int64
var svp, smvp *string
+ var slv, slmv interface{}
var ima []int64
var sma []string
if mv.Type() == v.Type() {
@@ -668,6 +669,9 @@
imv := toTimeUnix(mv)
imvp = &imv
}
+ case reflect.Array, reflect.Slice:
+ slv = v.Interface()
+ slmv = mv.Interface()
}
} else {
if mv.Kind() != reflect.Array && mv.Kind() != reflect.Slice {
@@ -765,8 +769,24 @@
return !r, nil
}
return r, nil
+ case "intersect":
+ r, err := intersect(slv, slmv)
+ if err != nil {
+ return false, err
+ }
+
+ if reflect.TypeOf(r).Kind() == reflect.Slice {
+ s := reflect.ValueOf(r)
+
+ if s.Len() > 0 {
+ return true, nil
+ }
+ return false, nil
+ } else {
+ return false, errors.New("invalid intersect values")
+ }
default:
- return false, errors.New("no such an operator")
+ return false, errors.New("no such operator")
}
return false, nil
}
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -18,11 +18,6 @@
"encoding/base64"
"errors"
"fmt"
- "github.com/spf13/afero"
- "github.com/spf13/cast"
- "github.com/spf13/hugo/hugofs"
- "github.com/spf13/viper"
- "github.com/stretchr/testify/assert"
"html/template"
"math/rand"
"path"
@@ -32,6 +27,12 @@
"strings"
"testing"
"time"
+
+ "github.com/spf13/afero"
+ "github.com/spf13/cast"
+ "github.com/spf13/hugo/hugofs"
+ "github.com/spf13/viper"
+ "github.com/stretchr/testify/assert"
)
type tstNoStringer struct {
@@ -1200,6 +1201,78 @@
key: "b", op: "in", match: []int{3, 4, 5},
expect: []map[string]int{
{"a": 3, "b": 4},
+ },
+ },
+ {
+ sequence: []map[string][]string{
+ {"a": []string{"A", "B", "C"}, "b": []string{"D", "E", "F"}}, {"a": []string{"G", "H", "I"}, "b": []string{"J", "K", "L"}}, {"a": []string{"M", "N", "O"}, "b": []string{"P", "Q", "R"}},
+ },
+ key: "b", op: "intersect", match: []string{"D", "P", "Q"},
+ expect: []map[string][]string{
+ {"a": []string{"A", "B", "C"}, "b": []string{"D", "E", "F"}}, {"a": []string{"M", "N", "O"}, "b": []string{"P", "Q", "R"}},
+ },
+ },
+ {
+ sequence: []map[string][]int{
+ {"a": []int{1, 2, 3}, "b": []int{4, 5, 6}}, {"a": []int{7, 8, 9}, "b": []int{10, 11, 12}}, {"a": []int{13, 14, 15}, "b": []int{16, 17, 18}},
+ },
+ key: "b", op: "intersect", match: []int{4, 10, 12},
+ expect: []map[string][]int{
+ {"a": []int{1, 2, 3}, "b": []int{4, 5, 6}}, {"a": []int{7, 8, 9}, "b": []int{10, 11, 12}},
+ },
+ },
+ {
+ sequence: []map[string][]int8{
+ {"a": []int8{1, 2, 3}, "b": []int8{4, 5, 6}}, {"a": []int8{7, 8, 9}, "b": []int8{10, 11, 12}}, {"a": []int8{13, 14, 15}, "b": []int8{16, 17, 18}},
+ },
+ key: "b", op: "intersect", match: []int8{4, 10, 12},
+ expect: []map[string][]int8{
+ {"a": []int8{1, 2, 3}, "b": []int8{4, 5, 6}}, {"a": []int8{7, 8, 9}, "b": []int8{10, 11, 12}},
+ },
+ },
+ {
+ sequence: []map[string][]int16{
+ {"a": []int16{1, 2, 3}, "b": []int16{4, 5, 6}}, {"a": []int16{7, 8, 9}, "b": []int16{10, 11, 12}}, {"a": []int16{13, 14, 15}, "b": []int16{16, 17, 18}},
+ },
+ key: "b", op: "intersect", match: []int16{4, 10, 12},
+ expect: []map[string][]int16{
+ {"a": []int16{1, 2, 3}, "b": []int16{4, 5, 6}}, {"a": []int16{7, 8, 9}, "b": []int16{10, 11, 12}},
+ },
+ },
+ {
+ sequence: []map[string][]int32{
+ {"a": []int32{1, 2, 3}, "b": []int32{4, 5, 6}}, {"a": []int32{7, 8, 9}, "b": []int32{10, 11, 12}}, {"a": []int32{13, 14, 15}, "b": []int32{16, 17, 18}},
+ },
+ key: "b", op: "intersect", match: []int32{4, 10, 12},
+ expect: []map[string][]int32{
+ {"a": []int32{1, 2, 3}, "b": []int32{4, 5, 6}}, {"a": []int32{7, 8, 9}, "b": []int32{10, 11, 12}},
+ },
+ },
+ {
+ sequence: []map[string][]int64{
+ {"a": []int64{1, 2, 3}, "b": []int64{4, 5, 6}}, {"a": []int64{7, 8, 9}, "b": []int64{10, 11, 12}}, {"a": []int64{13, 14, 15}, "b": []int64{16, 17, 18}},
+ },
+ key: "b", op: "intersect", match: []int64{4, 10, 12},
+ expect: []map[string][]int64{
+ {"a": []int64{1, 2, 3}, "b": []int64{4, 5, 6}}, {"a": []int64{7, 8, 9}, "b": []int64{10, 11, 12}},
+ },
+ },
+ {
+ sequence: []map[string][]float32{
+ {"a": []float32{1.0, 2.0, 3.0}, "b": []float32{4.0, 5.0, 6.0}}, {"a": []float32{7.0, 8.0, 9.0}, "b": []float32{10.0, 11.0, 12.0}}, {"a": []float32{13.0, 14.0, 15.0}, "b": []float32{16.0, 17.0, 18.0}},
+ },
+ key: "b", op: "intersect", match: []float32{4, 10, 12},
+ expect: []map[string][]float32{
+ {"a": []float32{1.0, 2.0, 3.0}, "b": []float32{4.0, 5.0, 6.0}}, {"a": []float32{7.0, 8.0, 9.0}, "b": []float32{10.0, 11.0, 12.0}},
+ },
+ },
+ {
+ sequence: []map[string][]float64{
+ {"a": []float64{1.0, 2.0, 3.0}, "b": []float64{4.0, 5.0, 6.0}}, {"a": []float64{7.0, 8.0, 9.0}, "b": []float64{10.0, 11.0, 12.0}}, {"a": []float64{13.0, 14.0, 15.0}, "b": []float64{16.0, 17.0, 18.0}},
+ },
+ key: "b", op: "intersect", match: []float64{4, 10, 12},
+ expect: []map[string][]float64{
+ {"a": []float64{1.0, 2.0, 3.0}, "b": []float64{4.0, 5.0, 6.0}}, {"a": []float64{7.0, 8.0, 9.0}, "b": []float64{10.0, 11.0, 12.0}},
},
},
{