hugo

Unnamed repository; edit this file 'description' to name the repository.

git clone git://git.shimmy1996.com/hugo.git
commit 09038865c24f420ac059a5cb8172da04c0391e58
parent ffbd2b6c67fd92305e4fc3c2ee580f731bc24cc1
Author: Christopher Mancini <cmancini@basho.com>
Date:   Mon, 11 Apr 2016 16:58:27 -0400

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

Diffstat:
Mdocs/content/templates/functions.md | 18+++++++++++++-----
Mtpl/template_funcs.go | 22+++++++++++++++++++++-
Mtpl/template_funcs_test.go | 83++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 112 insertions(+), 11 deletions(-)
diff --git a/docs/content/templates/functions.md b/docs/content/templates/functions.md
@@ -67,7 +67,7 @@ Creates a dictionary `(map[string, interface{})`, expects parameters added in va
 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 @@ e.g. Pass into "foo.html" a map with the keys "important, content"
 
     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,6 +312,15 @@ Following operators are now available
 - `<`, `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.:*
 
@@ -340,7 +348,7 @@ e.g.
 
 ### 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 @@ So, If the project working dir has a single file named `README.txt`:
 ### 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
diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go
@@ -646,6 +646,7 @@ func checkCondition(v, mv reflect.Value, op string) (bool, error) {
 
 	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 @@ func checkCondition(v, mv reflect.Value, op string) (bool, error) {
 				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 @@ func checkCondition(v, mv reflect.Value, op string) (bool, error) {
 			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
 }
diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go
@@ -18,11 +18,6 @@ import (
 	"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 @@ import (
 	"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 {
@@ -1203,6 +1204,78 @@ func TestWhere(t *testing.T) {
 			},
 		},
 		{
+			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}},
+			},
+		},
+		{
 			sequence: []map[string]int{
 				{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
 			},