ref: 0be2aade99a4e7d16a48cb4372d383a3d1748d10
parent: 358dcce7a6b4a8100964597f81cf371451f6c4d3
author: bep <[email protected]>
date: Tue Feb 24 05:56:16 EST 2015
Add Seq template func Very similar to GNU's seq. Fixes #552 Conflicts: tpl/template.go
--- a/helpers/general.go
+++ b/helpers/general.go
@@ -19,6 +19,7 @@
"encoding/hex"
"errors"
"fmt"
+ "github.com/spf13/cast"
bp "github.com/spf13/hugo/bufferpool"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper"
@@ -157,6 +158,74 @@
h := md5.New()
h.Write([]byte(f))
return hex.EncodeToString(h.Sum([]byte{}))
+}
+
+// Seq creates a sequence of integers.
+// It's named and used as GNU's seq.
+// Examples:
+// 3 => 1, 2, 3
+// 1 2 4 => 1, 3
+// -3 => -1, -2, -3
+// 1 4 => 1, 2, 3, 4
+// 1 -2 => 1, 0, -1, -2
+func Seq(args ...interface{}) ([]int, error) {
+ if len(args) < 1 || len(args) > 3 {
+ return nil, errors.New("Seq, invalid number of args: 'first' 'increment' (optional) 'last' (optional)")
+ }
+
+ intArgs := cast.ToIntSlice(args)
+
+ var inc int = 1
+ var last int
+ var first = intArgs[0]
+
+ if len(intArgs) == 1 {
+ last = first
+ if last == 0 {
+ return []int{}, nil
+ } else if last > 0 {
+ first = 1
+ } else {
+ first = -1
+ inc = -1
+ }
+ } else if len(intArgs) == 2 {
+ last = intArgs[1]
+ if last < first {
+ inc = -1
+ }
+ } else {
+ inc = intArgs[1]
+ last = intArgs[2]
+ if inc == 0 {
+ return nil, errors.New("'increment' must not be 0")
+ }
+ if first < last && inc < 0 {
+ return nil, errors.New("'increment' must be > 0")
+ }
+ if first > last && inc > 0 {
+ return nil, errors.New("'increment' must be < 0")
+ }
+ }
+
+ size := int(((last - first) / inc) + 1)
+
+ // sanity check
+ if size > 2000 {
+ return nil, errors.New("size of result exeeds limit")
+ }
+
+ seq := make([]int, size)
+ val := first
+ for i := 0; ; i++ {
+ seq[i] = val
+ val += inc
+ if (inc < 0 && val < last) || (inc > 0 && val > last) {
+ break
+ }
+ }
+
+ return seq, nil
}
// DoArithmetic performs arithmetic operations (+,-,*,/) using reflection to
--- a/helpers/general_test.go
+++ b/helpers/general_test.go
@@ -133,6 +133,49 @@
}
}
+func TestSeq(t *testing.T) {
+ for i, this := range []struct {
+ in []interface{}
+ expect interface{}
+ }{
+ {[]interface{}{-2, 5}, []int{-2, -1, 0, 1, 2, 3, 4, 5}},
+ {[]interface{}{1, 2, 4}, []int{1, 3}},
+ {[]interface{}{1}, []int{1}},
+ {[]interface{}{3}, []int{1, 2, 3}},
+ {[]interface{}{3.2}, []int{1, 2, 3}},
+ {[]interface{}{0}, []int{}},
+ {[]interface{}{-1}, []int{-1}},
+ {[]interface{}{-3}, []int{-1, -2, -3}},
+ {[]interface{}{3, -2}, []int{3, 2, 1, 0, -1, -2}},
+ {[]interface{}{6, -2, 2}, []int{6, 4, 2}},
+ {[]interface{}{1, 0, 2}, false},
+ {[]interface{}{1, -1, 2}, false},
+ {[]interface{}{2, 1, 1}, false},
+ {[]interface{}{2, 1, 1, 1}, false},
+ {[]interface{}{2001}, false},
+ {[]interface{}{}, false},
+ {[]interface{}{t}, []int{}},
+ {nil, false},
+ } {
+
+ result, err := Seq(this.in...)
+
+ if b, ok := this.expect.(bool); ok && !b {
+ if err == nil {
+ t.Errorf("[%d] TestSeq didn't return an expected error %s", i)
+ }
+ } else {
+ if err != nil {
+ t.Errorf("[%d] failed: %s", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(result, this.expect) {
+ t.Errorf("[%d] TestSeq got %v but expected %v", i, result, this.expect)
+ }
+ }
+ }
+}
+
func TestDoArithmetic(t *testing.T) {
for i, this := range []struct {
a interface{}
--- a/tpl/template.go
+++ b/tpl/template.go
@@ -1340,6 +1340,7 @@
"getJson": GetJSON,
"getCSV": GetCSV,
"getCsv": GetCSV,
+ "seq": helpers.Seq,
}
}