shithub: hugo

Download patch

ref: 601a2ce124b8ba93715e219d868435b9d255a9ab
parent: beaa09a7f646110ba14cc6ae3cd0d342ebb93740
author: Tatsushi Demachi <[email protected]>
date: Tue May 26 15:33:32 EDT 2015

Add `time.Time` type support to `where` tpl func

`where` tpl function doesn't support `time.Time` type so if people want
to compare such values, it's required that these values are converted
into `int` and compare them.

This improves it. If `time.Time` values are passed to `where`, it
converts them into `int` internally, compares them and returns the
result.

See also
http://discuss.gohugo.io/t/future-posts-and-past-posts/1229/3

--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -17,9 +17,6 @@
 	"bytes"
 	"errors"
 	"fmt"
-	"github.com/spf13/cast"
-	"github.com/spf13/hugo/helpers"
-	jww "github.com/spf13/jwalterweatherman"
 	"html"
 	"html/template"
 	"os"
@@ -27,6 +24,11 @@
 	"sort"
 	"strconv"
 	"strings"
+	"time"
+
+	"github.com/spf13/cast"
+	"github.com/spf13/hugo/helpers"
+	jww "github.com/spf13/jwalterweatherman"
 )
 
 var funcMap template.FuncMap
@@ -364,8 +366,16 @@
 var (
 	zero      reflect.Value
 	errorType = reflect.TypeOf((*error)(nil)).Elem()
+	timeType  = reflect.TypeOf((*time.Time)(nil)).Elem()
 )
 
+func timeUnix(v reflect.Value) int64 {
+	if v.Type() != timeType {
+		panic("coding error: argument must be time.Time type reflect Value")
+	}
+	return v.MethodByName("Unix").Call([]reflect.Value{})[0].Int()
+}
+
 func evaluateSubElem(obj reflect.Value, elemName string) (reflect.Value, error) {
 	if !obj.IsValid() {
 		return zero, errors.New("can't evaluate an invalid value")
@@ -459,6 +469,14 @@
 			svp = &sv
 			smv := mv.String()
 			smvp = &smv
+		case reflect.Struct:
+			switch v.Type() {
+			case timeType:
+				iv := timeUnix(v)
+				ivp = &iv
+				imv := timeUnix(mv)
+				imvp = &imv
+			}
 		}
 	} else {
 		if mv.Kind() != reflect.Array && mv.Kind() != reflect.Slice {
@@ -479,6 +497,15 @@
 			svp = &sv
 			for i := 0; i < mv.Len(); i++ {
 				sma = append(sma, mv.Index(i).String())
+			}
+		case reflect.Struct:
+			switch v.Type() {
+			case timeType:
+				iv := timeUnix(v)
+				ivp = &iv
+				for i := 0; i < mv.Len(); i++ {
+					ima = append(ima, timeUnix(mv.Index(i)))
+				}
 			}
 		}
 	}
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -479,6 +479,28 @@
 	unexported string
 }
 
+func TestTimeUnix(t *testing.T) {
+	var sec int64 = 1234567890
+	tv := reflect.ValueOf(time.Unix(sec, 0))
+	i := 1
+
+	res := timeUnix(tv)
+	if sec != res {
+		t.Errorf("[%d] timeUnix got %v but expected %v", i, res, sec)
+	}
+
+	i++
+	func(t *testing.T) {
+		defer func() {
+			if err := recover(); err == nil {
+				t.Errorf("[%d] timeUnix didn't return an expected error", i)
+			}
+		}()
+		iv := reflect.ValueOf(sec)
+		timeUnix(iv)
+	}(t)
+}
+
 func TestEvaluateSubElem(t *testing.T) {
 	tstx := TstX{A: "foo", B: "bar"}
 	var inner struct {
@@ -543,20 +565,76 @@
 	}{
 		{reflect.ValueOf(123), reflect.ValueOf(123), "", expect{true, false}},
 		{reflect.ValueOf("foo"), reflect.ValueOf("foo"), "", expect{true, false}},
+		{
+			reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
+			reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
+			"",
+			expect{true, false},
+		},
 		{reflect.ValueOf(123), reflect.ValueOf(456), "!=", expect{true, false}},
 		{reflect.ValueOf("foo"), reflect.ValueOf("bar"), "!=", expect{true, false}},
+		{
+			reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
+			reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
+			"!=",
+			expect{true, false},
+		},
 		{reflect.ValueOf(456), reflect.ValueOf(123), ">=", expect{true, false}},
 		{reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">=", expect{true, false}},
+		{
+			reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
+			reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
+			">=",
+			expect{true, false},
+		},
 		{reflect.ValueOf(456), reflect.ValueOf(123), ">", expect{true, false}},
 		{reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">", expect{true, false}},
+		{
+			reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
+			reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
+			">",
+			expect{true, false},
+		},
 		{reflect.ValueOf(123), reflect.ValueOf(456), "<=", expect{true, false}},
 		{reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<=", expect{true, false}},
+		{
+			reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
+			reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
+			"<=",
+			expect{true, false},
+		},
 		{reflect.ValueOf(123), reflect.ValueOf(456), "<", expect{true, false}},
 		{reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<", expect{true, false}},
+		{
+			reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
+			reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
+			"<",
+			expect{true, false},
+		},
 		{reflect.ValueOf(123), reflect.ValueOf([]int{123, 45, 678}), "in", expect{true, false}},
 		{reflect.ValueOf("foo"), reflect.ValueOf([]string{"foo", "bar", "baz"}), "in", expect{true, false}},
+		{
+			reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
+			reflect.ValueOf([]time.Time{
+				time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC),
+				time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC),
+				time.Date(2015, time.June, 26, 19, 18, 56, 12345, time.UTC),
+			}),
+			"in",
+			expect{true, false},
+		},
 		{reflect.ValueOf(123), reflect.ValueOf([]int{45, 678}), "not in", expect{true, false}},
 		{reflect.ValueOf("foo"), reflect.ValueOf([]string{"bar", "baz"}), "not in", expect{true, false}},
+		{
+			reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
+			reflect.ValueOf([]time.Time{
+				time.Date(2015, time.February, 26, 19, 18, 56, 12345, time.UTC),
+				time.Date(2015, time.March, 26, 19, 18, 56, 12345, time.UTC),
+				time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC),
+			}),
+			"not in",
+			expect{true, false},
+		},
 		{reflect.ValueOf("foo"), reflect.ValueOf("bar-foo-baz"), "in", expect{true, false}},
 		{reflect.ValueOf("foo"), reflect.ValueOf("bar--baz"), "not in", expect{true, false}},
 		{reflect.Value{}, reflect.ValueOf("foo"), "", expect{false, false}},