summaryrefslogtreecommitdiffstats
path: root/tpl
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-07-06 14:12:10 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-07-06 17:51:38 +0200
commit2b8d907ab731627f4e2a30442cd729064516c8bb (patch)
tree2f9235dfbcf116c463b75d59c8be1be53d55b05a /tpl
parent43338c3a99769eb7d0df0c12559b8b3d42b67dba (diff)
Add a newScratch template func
Fixes #4685
Diffstat (limited to 'tpl')
-rw-r--r--tpl/collections/collections.go7
-rw-r--r--tpl/collections/init.go8
-rw-r--r--tpl/math/math.go127
-rw-r--r--tpl/math/math_test.go87
-rw-r--r--tpl/tplimpl/template_funcs_test.go1
5 files changed, 21 insertions, 209 deletions
diff --git a/tpl/collections/collections.go b/tpl/collections/collections.go
index dd418d7d2..51bc5c796 100644
--- a/tpl/collections/collections.go
+++ b/tpl/collections/collections.go
@@ -23,6 +23,7 @@ import (
"strings"
"time"
+ "github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/deps"
"github.com/gohugoio/hugo/helpers"
@@ -650,3 +651,9 @@ func (ns *Namespace) Uniq(l interface{}) (interface{}, error) {
func (ns *Namespace) KeyVals(key interface{}, vals ...interface{}) (types.KeyValues, error) {
return types.KeyValues{Key: key, Values: vals}, nil
}
+
+// NewScratch creates a new Scratch which can be used to store values in a
+// thread safe way.
+func (ns *Namespace) NewScratch() *maps.Scratch {
+ return maps.NewScratch()
+}
diff --git a/tpl/collections/init.go b/tpl/collections/init.go
index 91b0dea01..b986b3b42 100644
--- a/tpl/collections/init.go
+++ b/tpl/collections/init.go
@@ -144,6 +144,14 @@ func init() {
{`{{ seq 3 }}`, `[1 2 3]`},
},
)
+
+ ns.AddMethodMapping(ctx.NewScratch,
+ []string{"newScratch"},
+ [][2]string{
+ {`{{ $scratch := newScratch }}{{ $scratch.Add "b" 2 }}{{ $scratch.Add "b" 2 }}{{ $scratch.Get "b" }}`, `4`},
+ },
+ )
+
ns.AddMethodMapping(ctx.Uniq,
[]string{"uniq"},
[][2]string{
diff --git a/tpl/math/math.go b/tpl/math/math.go
index 534f7f284..fcc6abc3d 100644
--- a/tpl/math/math.go
+++ b/tpl/math/math.go
@@ -16,7 +16,8 @@ package math
import (
"errors"
"math"
- "reflect"
+
+ _math "github.com/gohugoio/hugo/common/math"
"github.com/spf13/cast"
)
@@ -31,7 +32,7 @@ type Namespace struct{}
// Add adds two numbers.
func (ns *Namespace) Add(a, b interface{}) (interface{}, error) {
- return DoArithmetic(a, b, '+')
+ return _math.DoArithmetic(a, b, '+')
}
// Ceil returns the least integer value greater than or equal to x.
@@ -46,7 +47,7 @@ func (ns *Namespace) Ceil(x interface{}) (float64, error) {
// Div divides two numbers.
func (ns *Namespace) Div(a, b interface{}) (interface{}, error) {
- return DoArithmetic(a, b, '/')
+ return _math.DoArithmetic(a, b, '/')
}
// Floor returns the greatest integer value less than or equal to x.
@@ -98,7 +99,7 @@ func (ns *Namespace) ModBool(a, b interface{}) (bool, error) {
// Mul multiplies two numbers.
func (ns *Namespace) Mul(a, b interface{}) (interface{}, error) {
- return DoArithmetic(a, b, '*')
+ return _math.DoArithmetic(a, b, '*')
}
// Round returns the nearest integer, rounding half away from zero.
@@ -113,121 +114,5 @@ func (ns *Namespace) Round(x interface{}) (float64, error) {
// Sub subtracts two numbers.
func (ns *Namespace) Sub(a, b interface{}) (interface{}, error) {
- return DoArithmetic(a, b, '-')
-}
-
-// DoArithmetic performs arithmetic operations (+,-,*,/) using reflection to
-// determine the type of the two terms.
-func DoArithmetic(a, b interface{}, op rune) (interface{}, error) {
- av := reflect.ValueOf(a)
- bv := reflect.ValueOf(b)
- var ai, bi int64
- var af, bf float64
- var au, bu uint64
- switch av.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- ai = av.Int()
- switch bv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- bi = bv.Int()
- case reflect.Float32, reflect.Float64:
- af = float64(ai) // may overflow
- ai = 0
- bf = bv.Float()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- bu = bv.Uint()
- if ai >= 0 {
- au = uint64(ai)
- ai = 0
- } else {
- bi = int64(bu) // may overflow
- bu = 0
- }
- default:
- return nil, errors.New("Can't apply the operator to the values")
- }
- case reflect.Float32, reflect.Float64:
- af = av.Float()
- switch bv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- bf = float64(bv.Int()) // may overflow
- case reflect.Float32, reflect.Float64:
- bf = bv.Float()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- bf = float64(bv.Uint()) // may overflow
- default:
- return nil, errors.New("Can't apply the operator to the values")
- }
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- au = av.Uint()
- switch bv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- bi = bv.Int()
- if bi >= 0 {
- bu = uint64(bi)
- bi = 0
- } else {
- ai = int64(au) // may overflow
- au = 0
- }
- case reflect.Float32, reflect.Float64:
- af = float64(au) // may overflow
- au = 0
- bf = bv.Float()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- bu = bv.Uint()
- default:
- return nil, errors.New("Can't apply the operator to the values")
- }
- case reflect.String:
- as := av.String()
- if bv.Kind() == reflect.String && op == '+' {
- bs := bv.String()
- return as + bs, nil
- }
- return nil, errors.New("Can't apply the operator to the values")
- default:
- return nil, errors.New("Can't apply the operator to the values")
- }
-
- switch op {
- case '+':
- if ai != 0 || bi != 0 {
- return ai + bi, nil
- } else if af != 0 || bf != 0 {
- return af + bf, nil
- } else if au != 0 || bu != 0 {
- return au + bu, nil
- }
- return 0, nil
- case '-':
- if ai != 0 || bi != 0 {
- return ai - bi, nil
- } else if af != 0 || bf != 0 {
- return af - bf, nil
- } else if au != 0 || bu != 0 {
- return au - bu, nil
- }
- return 0, nil
- case '*':
- if ai != 0 || bi != 0 {
- return ai * bi, nil
- } else if af != 0 || bf != 0 {
- return af * bf, nil
- } else if au != 0 || bu != 0 {
- return au * bu, nil
- }
- return 0, nil
- case '/':
- if bi != 0 {
- return ai / bi, nil
- } else if bf != 0 {
- return af / bf, nil
- } else if bu != 0 {
- return au / bu, nil
- }
- return nil, errors.New("Can't divide the value by 0")
- default:
- return nil, errors.New("There is no such an operation")
- }
+ return _math.DoArithmetic(a, b, '-')
}
diff --git a/tpl/math/math_test.go b/tpl/math/math_test.go
index 97acfaeba..f2e6236af 100644
--- a/tpl/math/math_test.go
+++ b/tpl/math/math_test.go
@@ -56,93 +56,6 @@ func TestBasicNSArithmetic(t *testing.T) {
}
}
-func TestDoArithmetic(t *testing.T) {
- t.Parallel()
-
- for i, test := range []struct {
- a interface{}
- b interface{}
- op rune
- expect interface{}
- }{
- {3, 2, '+', int64(5)},
- {3, 2, '-', int64(1)},
- {3, 2, '*', int64(6)},
- {3, 2, '/', int64(1)},
- {3.0, 2, '+', float64(5)},
- {3.0, 2, '-', float64(1)},
- {3.0, 2, '*', float64(6)},
- {3.0, 2, '/', float64(1.5)},
- {3, 2.0, '+', float64(5)},
- {3, 2.0, '-', float64(1)},
- {3, 2.0, '*', float64(6)},
- {3, 2.0, '/', float64(1.5)},
- {3.0, 2.0, '+', float64(5)},
- {3.0, 2.0, '-', float64(1)},
- {3.0, 2.0, '*', float64(6)},
- {3.0, 2.0, '/', float64(1.5)},
- {uint(3), uint(2), '+', uint64(5)},
- {uint(3), uint(2), '-', uint64(1)},
- {uint(3), uint(2), '*', uint64(6)},
- {uint(3), uint(2), '/', uint64(1)},
- {uint(3), 2, '+', uint64(5)},
- {uint(3), 2, '-', uint64(1)},
- {uint(3), 2, '*', uint64(6)},
- {uint(3), 2, '/', uint64(1)},
- {3, uint(2), '+', uint64(5)},
- {3, uint(2), '-', uint64(1)},
- {3, uint(2), '*', uint64(6)},
- {3, uint(2), '/', uint64(1)},
- {uint(3), -2, '+', int64(1)},
- {uint(3), -2, '-', int64(5)},
- {uint(3), -2, '*', int64(-6)},
- {uint(3), -2, '/', int64(-1)},
- {-3, uint(2), '+', int64(-1)},
- {-3, uint(2), '-', int64(-5)},
- {-3, uint(2), '*', int64(-6)},
- {-3, uint(2), '/', int64(-1)},
- {uint(3), 2.0, '+', float64(5)},
- {uint(3), 2.0, '-', float64(1)},
- {uint(3), 2.0, '*', float64(6)},
- {uint(3), 2.0, '/', float64(1.5)},
- {3.0, uint(2), '+', float64(5)},
- {3.0, uint(2), '-', float64(1)},
- {3.0, uint(2), '*', float64(6)},
- {3.0, uint(2), '/', float64(1.5)},
- {0, 0, '+', 0},
- {0, 0, '-', 0},
- {0, 0, '*', 0},
- {"foo", "bar", '+', "foobar"},
- {3, 0, '/', false},
- {3.0, 0, '/', false},
- {3, 0.0, '/', false},
- {uint(3), uint(0), '/', false},
- {3, uint(0), '/', false},
- {-3, uint(0), '/', false},
- {uint(3), 0, '/', false},
- {3.0, uint(0), '/', false},
- {uint(3), 0.0, '/', false},
- {3, "foo", '+', false},
- {3.0, "foo", '+', false},
- {uint(3), "foo", '+', false},
- {"foo", 3, '+', false},
- {"foo", "bar", '-', false},
- {3, 2, '%', false},
- } {
- errMsg := fmt.Sprintf("[%d] %v", i, test)
-
- result, err := DoArithmetic(test.a, test.b, test.op)
-
- if b, ok := test.expect.(bool); ok && !b {
- require.Error(t, err, errMsg)
- continue
- }
-
- require.NoError(t, err, errMsg)
- assert.Equal(t, test.expect, result, errMsg)
- }
-}
-
func TestCeil(t *testing.T) {
t.Parallel()
diff --git a/tpl/tplimpl/template_funcs_test.go b/tpl/tplimpl/template_funcs_test.go
index 341be805a..8594c67a4 100644
--- a/tpl/tplimpl/template_funcs_test.go
+++ b/tpl/tplimpl/template_funcs_test.go
@@ -125,7 +125,6 @@ func TestTemplateFuncsExamples(t *testing.T) {
}
}
}
-
}
// TODO(bep) it would be dandy to put this one into the partials package, but