mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
Add Seq template func
Very similar to GNU's seq. Fixes #552 Conflicts: tpl/template.go
This commit is contained in:
parent
358dcce7a6
commit
0be2aade99
3 changed files with 113 additions and 0 deletions
|
@ -19,6 +19,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/spf13/cast"
|
||||||
bp "github.com/spf13/hugo/bufferpool"
|
bp "github.com/spf13/hugo/bufferpool"
|
||||||
jww "github.com/spf13/jwalterweatherman"
|
jww "github.com/spf13/jwalterweatherman"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
@ -159,6 +160,74 @@ func Md5String(f string) string {
|
||||||
return hex.EncodeToString(h.Sum([]byte{}))
|
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
|
// DoArithmetic performs arithmetic operations (+,-,*,/) using reflection to
|
||||||
// determine the type of the two terms.
|
// determine the type of the two terms.
|
||||||
func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
|
func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
|
||||||
|
|
|
@ -133,6 +133,49 @@ func TestMd5StringEmpty(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
func TestDoArithmetic(t *testing.T) {
|
||||||
for i, this := range []struct {
|
for i, this := range []struct {
|
||||||
a interface{}
|
a interface{}
|
||||||
|
|
|
@ -1340,6 +1340,7 @@ func init() {
|
||||||
"getJson": GetJSON,
|
"getJson": GetJSON,
|
||||||
"getCSV": GetCSV,
|
"getCSV": GetCSV,
|
||||||
"getCsv": GetCSV,
|
"getCsv": GetCSV,
|
||||||
|
"seq": helpers.Seq,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue