shithub: hugo

Download patch

ref: af47e5a2cfc5441005cccbb1684f3850a0f62bd1
parent: d4ed59198a5e01010269ddd1f0b281bdfad8f46c
author: Tatsushi Demachi <[email protected]>
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{}) error
 	Lookup(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{}