summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Sharfi <adiabatic@users.noreply.github.com>2017-05-29 12:03:38 -0700
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-06-03 19:13:58 +0200
commite28d9aa42c3429d22fe254e69e4605aaf1e684f3 (patch)
tree031bbf501c469655fe57db27a1bb4b7014f62c18
parent46b4607828923c5d4d04dd386fc0ee5132f505ca (diff)
tpl: Add uniq function
-rw-r--r--docs/content/templates/functions.md9
-rw-r--r--tpl/collections/collections.go38
-rw-r--r--tpl/collections/collections_test.go36
-rw-r--r--tpl/collections/init.go6
4 files changed, 89 insertions, 0 deletions
diff --git a/docs/content/templates/functions.md b/docs/content/templates/functions.md
index c514a4ec8..a1cf9e27b 100644
--- a/docs/content/templates/functions.md
+++ b/docs/content/templates/functions.md
@@ -373,6 +373,15 @@ e.g.
{{ .Content }}
{{ end }}
+
+### uniq
+
+Takes in a slice or array and returns a slice with subsequent duplicate elements removed.
+
+ {{ uniq (slice 1 2 3 2) }}
+ {{ slice 1 2 3 2 | uniq }}
+ <!-- both return [1 2 3] -->
+
## Files
### readDir
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