ref: af47e5a2cfc5441005cccbb1684f3850a0f62bd1
parent: d4ed59198a5e01010269ddd1f0b281bdfad8f46c
author: Tatsushi Demachi <tdemachi@gmail.com>
date: Tue Oct 21 20:51:29 EDT 2014
Extend template's mod and modBool functions to accept any int types Fixes #575
--- a/hugolib/template.go
+++ b/hugolib/template.go
@@ -446,6 +446,40 @@
}
}
+func Mod(a, b interface{}) (int64, error) {+ av := reflect.ValueOf(a)
+ bv := reflect.ValueOf(b)
+ var ai, bi int64
+
+ switch av.Kind() {+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ ai = av.Int()
+ default:
+ return 0, errors.New("Modulo operator can't be used with non integer value")+ }
+
+ switch bv.Kind() {+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ bi = bv.Int()
+ default:
+ return 0, errors.New("Modulo operator can't be used with non integer value")+ }
+
+ if bi == 0 {+ return 0, errors.New("The number can't be divided by zero at modulo operation")+ }
+
+ return ai % bi, nil
+}
+
+func ModBool(a, b interface{}) (bool, error) {+ res, err := Mod(a, b)
+ if err != nil {+ return false, err
+ }
+ return res == int64(0), nil
+}
+
type Template interface { ExecuteTemplate(wr io.Writer, name string, data interface{}) errorLookup(name string) *template.Template
@@ -496,9 +530,9 @@
"add": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '+') }, "sub": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '-') }, "div": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '/') },- "mod": func(a, b int) int { return a % b },+ "mod": Mod,
"mul": func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '*') },- "modBool": func(a, b int) bool { return a%b == 0 },+ "modBool": ModBool,
"lower": func(a string) string { return strings.ToLower(a) }, "upper": func(a string) string { return strings.ToUpper(a) }, "title": func(a string) string { return strings.Title(a) },--- a/hugolib/template_test.go
+++ b/hugolib/template_test.go
@@ -123,6 +123,81 @@
}
}
+func TestMod(t *testing.T) {+ for i, this := range []struct {+ a interface{}+ b interface{}+ expect interface{}+ }{+ {3, 2, int64(1)},+ {3, 1, int64(0)},+ {3, 0, false},+ {0, 3, int64(0)},+ {3.1, 2, false},+ {3, 2.1, false},+ {3.1, 2.1, false},+ {int8(3), int8(2), int64(1)},+ {int16(3), int16(2), int64(1)},+ {int32(3), int32(2), int64(1)},+ {int64(3), int64(2), int64(1)},+ } {+ result, err := Mod(this.a, this.b)
+ if b, ok := this.expect.(bool); ok && !b {+ if err == nil {+ t.Errorf("[%d] modulo didn't return an expected error")+ }
+ } else {+ if err != nil {+ t.Errorf("[%d] failed: %s", i, err)+ continue
+ }
+ if !reflect.DeepEqual(result, this.expect) {+ t.Errorf("[%d] modulo got %v but expected %v", i, result, this.expect)+ }
+ }
+ }
+}
+
+func TestModBool(t *testing.T) {+ for i, this := range []struct {+ a interface{}+ b interface{}+ expect interface{}+ }{+ {3, 3, true},+ {3, 2, false},+ {3, 1, true},+ {3, 0, nil},+ {0, 3, true},+ {3.1, 2, nil},+ {3, 2.1, nil},+ {3.1, 2.1, nil},+ {int8(3), int8(3), true},+ {int8(3), int8(2), false},+ {int16(3), int16(3), true},+ {int16(3), int16(2), false},+ {int32(3), int32(3), true},+ {int32(3), int32(2), false},+ {int64(3), int64(3), true},+ {int64(3), int64(2), false},+ } {+ result, err := ModBool(this.a, this.b)
+ if this.expect == nil {+ if err == nil {+ t.Errorf("[%d] modulo didn't return an expected error")+ }
+ } else {+ if err != nil {+ t.Errorf("[%d] failed: %s", i, err)+ continue
+ }
+ if !reflect.DeepEqual(result, this.expect) {+ t.Errorf("[%d] modulo got %v but expected %v", i, result, this.expect)+ }
+ }
+ }
+}
+
func TestFirst(t *testing.T) { for i, this := range []struct { count interface{}--
⑨