Skip to content

Commit

Permalink
Adding math.Seq function
Browse files Browse the repository at this point in the history
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
  • Loading branch information
hairyhenderson committed Nov 3, 2017
1 parent ad2d0b1 commit 2c56ad7
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 1 deletion.
33 changes: 33 additions & 0 deletions docs/content/functions/math.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,36 @@ $ gomplate -i '{{ math.Pow 2 32 }}'
4294967296
```

## `math.Seq`

**Alias:** `seq`

Return a sequence from `start` to `end`, in steps of `step`. Can handle counting
down as well as up, including with negative numbers.

Note that the sequence _may_ not end at `end`, if `end` is not divisible by `step`.

### Usage
```go
math.Seq [start] end [step]
```

### Arguments

| name | description |
|--------|-------|
| `start` | _(optional)_ The first number in the sequence (defaults to `1`) |
| `end` | _(required)_ The last number in the sequence |
| `step` | _(optional)_ The amount to increment between each number (defaults to `1`) |

### Examples

```console
$ gomplate -i '{{ range (math.Seq 5) }}{{.}} {{end}}'
1 2 3 4 5
```

```console
$ gomplate -i '{{ conv.Join (math.Seq 10 -3 2) ", " }}'
10, 8, 6, 4, 2, 0, -2
```
25 changes: 25 additions & 0 deletions funcs/math.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func AddMathFuncs(f map[string]interface{}) {
f["div"] = MathNS().Div
f["rem"] = MathNS().Rem
f["pow"] = MathNS().Pow
f["seq"] = MathNS().Seq
}

// MathFuncs -
Expand Down Expand Up @@ -70,3 +71,27 @@ func (f *MathFuncs) Rem(a, b interface{}) int64 {
func (f *MathFuncs) Pow(a, b interface{}) int64 {
return conv.ToInt64(gmath.Pow(conv.ToFloat64(a), conv.ToFloat64(b)))
}

// Seq - return a sequence from `start` to `end`, in steps of `step`
// start and step are optional, and default to 1.
func (f *MathFuncs) Seq(n ...interface{}) ([]int64, error) {
start := int64(1)
end := int64(0)
step := int64(1)
if len(n) == 0 {
return nil, fmt.Errorf("math.Seq must be given at least an 'end' value")
}
if len(n) == 1 {
end = conv.ToInt64(n[0])
}
if len(n) == 2 {
start = conv.ToInt64(n[0])
end = conv.ToInt64(n[1])
}
if len(n) == 3 {
start = conv.ToInt64(n[0])
end = conv.ToInt64(n[1])
step = conv.ToInt64(n[2])
}
return math.Seq(conv.ToInt64(start), conv.ToInt64(end), conv.ToInt64(step)), nil
}
20 changes: 19 additions & 1 deletion funcs/math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,28 @@ func TestRem(t *testing.T) {
m := MathNS()
assert.Equal(t, int64(0), m.Rem(1, 1))
assert.Equal(t, int64(2), m.Rem(5, 3.0))
// assert.Equal(t, int64(1), m.Mod(true, "42"))
}

func TestPow(t *testing.T) {
m := MathNS()
assert.Equal(t, int64(4), m.Pow(2, "2"))
}

func mustSeq(n ...interface{}) []int64 {
m := MathNS()
s, err := m.Seq(n...)
if err != nil {
panic(err)
}
return s
}
func TestSeq(t *testing.T) {
m := MathNS()
assert.EqualValues(t, []int64{0, 1, 2, 3}, mustSeq(0, 3))
assert.EqualValues(t, []int64{1, 0}, mustSeq(0))
assert.EqualValues(t, []int64{0, 2, 4}, mustSeq(0, 4, 2))
assert.EqualValues(t, []int64{0, 2, 4}, mustSeq(0, 5, 2))
assert.EqualValues(t, []int64{0}, mustSeq(0, 5, 8))
_, err := m.Seq()
assert.Error(t, err)
}
27 changes: 27 additions & 0 deletions math/math.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,30 @@ func MulInt(n ...int64) int64 {
}
return x
}

// Seq - return a sequence from `start` to `end`, in steps of `step`.
func Seq(start, end, step int64) []int64 {
// a step of 0 just returns an empty sequence
if step == 0 {
return []int64{}
}

// handle cases where step has wrong sign
if end < start && step > 0 {
step = -step
}
if end > start && step < 0 {
step = -step
}

// adjust the end so it aligns exactly (avoids infinite loop!)
end = end - (end-start)%step

seq := []int64{start}
last := start
for last != end {
last = seq[len(seq)-1] + step
seq = append(seq, last)
}
return seq
}
17 changes: 17 additions & 0 deletions math/math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,20 @@ func TestMath(t *testing.T) {
assert.Equal(t, int64(10), AddInt(1, 2, 3, 4))
assert.Equal(t, int64(12), MulInt(3, 4, 1))
}

func TestSeq(t *testing.T) {
assert.EqualValues(t, []int64{1, 2, 3}, Seq(1, 3, 1))
assert.EqualValues(t, []int64{1, 3}, Seq(1, 3, 2))
assert.EqualValues(t, []int64{0, 2}, Seq(0, 3, 2))
assert.EqualValues(t, []int64{0, 2, 4}, Seq(0, 4, 2))
assert.EqualValues(t, []int64{0, -5, -10}, Seq(0, -10, -5))
assert.EqualValues(t, []int64{4, 3, 2, 1}, Seq(4, 1, 1))
assert.EqualValues(t, []int64{-2, -1, 0}, Seq(-2, 0, 1))
assert.EqualValues(t, []int64{-1, 0, 1}, Seq(-1, 1, 1))
assert.EqualValues(t, []int64{-1, 0, 1}, Seq(-1, 1, -1))
assert.EqualValues(t, []int64{1, 0, -1}, Seq(1, -1, 1))
assert.EqualValues(t, []int64{1, 0, -1}, Seq(1, -1, -1))
assert.EqualValues(t, []int64{}, Seq(1, -1, 0))
assert.EqualValues(t, []int64{1}, Seq(1, 10000, 10000))
assert.EqualValues(t, []int64{1, 0, -1}, Seq(1, -1, -1))
}
6 changes: 6 additions & 0 deletions test/integration/math.bats
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,10 @@ load helper
gomplate -i '{{ math.Pow 8 4 }} {{ pow 2 2 }}'
[ "$status" -eq 0 ]
[[ "${output}" == "4096 4" ]]
}

@test "'math.Seq'" {
gomplate -i '{{ math.Seq 0 }}, {{ seq 0 3 }}, {{ seq -5 -10 2 }}'
[ "$status" -eq 0 ]
[[ "${output}" == "[1 0], [0 1 2 3], [-5 -7 -9]" ]]
}

0 comments on commit 2c56ad7

Please sign in to comment.