summaryrefslogtreecommitdiffhomepage
path: root/tpl/collections
diff options
context:
space:
mode:
authorNathan Sharfi <[email protected]>2017-05-29 12:03:38 -0700
committerBjørn Erik Pedersen <[email protected]>2017-06-03 19:13:58 +0200
commite28d9aa42c3429d22fe254e69e4605aaf1e684f3 (patch)
tree031bbf501c469655fe57db27a1bb4b7014f62c18 /tpl/collections
parent46b4607828923c5d4d04dd386fc0ee5132f505ca (diff)
downloadhugo-e28d9aa42c3429d22fe254e69e4605aaf1e684f3.tar.gz
hugo-e28d9aa42c3429d22fe254e69e4605aaf1e684f3.zip
tpl: Add uniq function
Diffstat (limited to 'tpl/collections')
-rw-r--r--tpl/collections/collections.go38
-rw-r--r--tpl/collections/collections_test.go36
-rw-r--r--tpl/collections/init.go6
3 files changed, 80 insertions, 0 deletions
diff --git a/tpl/collections/collections.go b/tpl/collections/collections.go
index a6331edfe..b025c7670 100644
--- a/tpl/collections/collections.go
+++ b/tpl/collections/collections.go
@@ -587,3 +587,41 @@ func (ns *Namespace) Union(l1, l2 interface{}) (interface{}, error) {
return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
}
}
+
+// Uniq takes in a slice or array and returns a slice with subsequent
+// duplicate elements removed.
+func (ns *Namespace) Uniq(l interface{}) (interface{}, error) {
+ if l == nil {
+ return make([]interface{}, 0), nil
+ }
+
+ lv := reflect.ValueOf(l)
+ lv, isNil := indirect(lv)
+ if isNil {
+ return nil, errors.New("invalid nil argument to Uniq")
+ }
+
+ var ret reflect.Value
+
+ switch lv.Kind() {
+ case reflect.Slice:
+ ret = reflect.MakeSlice(lv.Type(), 0, 0)
+ case reflect.Array:
+ ret = reflect.MakeSlice(reflect.SliceOf(lv.Type().Elem()), 0, 0)
+ default:
+ return nil, errors.New("Can't use Uniq on " + reflect.ValueOf(lv).Type().String())
+ }
+
+ for i := 0; i != lv.Len(); i++ {
+ lvv := lv.Index(i)
+ lvv, isNil := indirect(lvv)
+ if isNil {
+ continue
+ }
+
+ if !ns.In(ret.Interface(), lvv.Interface()) {
+ ret = reflect.Append(ret, lvv)
+ }
+ }
+ return ret.Interface(), nil
+}
diff --git a/tpl/collections/collections_test.go b/tpl/collections/collections_test.go
index 6a3d7b9e4..9943f439e 100644
--- a/tpl/collections/collections_test.go
+++ b/tpl/collections/collections_test.go
@@ -603,6 +603,42 @@ func TestUnion(t *testing.T) {
}
}
+func TestUniq(t *testing.T) {
+ t.Parallel()
+
+ ns := New(&deps.Deps{})
+ for i, test := range []struct {
+ l interface{}
+ expect interface{}
+ isErr bool
+ }{
+ {[]string{"a", "b", "c"}, []string{"a", "b", "c"}, false},
+ {[]string{"a", "b", "c", "c"}, []string{"a", "b", "c"}, false},
+ {[]string{"a", "b", "b", "c"}, []string{"a", "b", "c"}, false},
+ {[]string{"a", "b", "c", "b"}, []string{"a", "b", "c"}, false},
+ {[]int{1, 2, 3}, []int{1, 2, 3}, false},
+ {[]int{1, 2, 3, 3}, []int{1, 2, 3}, false},
+ {[]int{1, 2, 2, 3}, []int{1, 2, 3}, false},
+ {[]int{1, 2, 3, 2}, []int{1, 2, 3}, false},
+ {[4]int{1, 2, 3, 2}, []int{1, 2, 3}, false},
+ {nil, make([]interface{}, 0), false},
+ // should-errors
+ {1, 1, true},
+ {"foo", "fo", true},
+ } {
+ errMsg := fmt.Sprintf("[%d] %v", i, test)
+
+ result, err := ns.Uniq(test.l)
+ if test.isErr {
+ assert.Error(t, err, errMsg)
+ continue
+ }
+
+ assert.NoError(t, err, errMsg)
+ assert.Equal(t, test.expect, result, errMsg)
+ }
+}
+
func (x *TstX) TstRp() string {
return "r" + x.A
}
diff --git a/tpl/collections/init.go b/tpl/collections/init.go
index fa786684b..25ef64e1a 100644
--- a/tpl/collections/init.go
+++ b/tpl/collections/init.go
@@ -137,6 +137,12 @@ func init() {
{`{{ seq 3 }}`, `[1 2 3]`},
},
)
+ ns.AddMethodMapping(ctx.Uniq,
+ []string{"uniq"},
+ [][2]string{
+ {`{{ slice 1 2 3 2 | uniq }}`, `[1 2 3]`},
+ },
+ )
return ns