Add `time.Time` type support to `where` tpl func
authorTatsushi Demachi <tdemachi@gmail.com>
Tue, 26 May 2015 10:33:32 +0000 (19:33 +0900)
committerbep <bjorn.erik.pedersen@gmail.com>
Tue, 26 May 2015 13:59:36 +0000 (15:59 +0200)
`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

tpl/template_funcs.go
tpl/template_funcs_test.go

index a78e4cce1d3f54c40729a9695a4f96eaf0f3158b..a5bd221e750ed39f975a4c28de9aac7ab7827efd 100644 (file)
@@ -17,9 +17,6 @@ import (
        "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 @@ import (
        "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 @@ func First(limit interface{}, seq interface{}) (interface{}, error) {
 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 @@ func checkCondition(v, mv reflect.Value, op string) (bool, error) {
                        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 {
@@ -480,6 +498,15 @@ func checkCondition(v, mv reflect.Value, op string) (bool, error) {
                        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)))
+                               }
+                       }
                }
        }
 
index cedbf0f31b5d81516a27dfdbd5cd5e2926619685..a3c20290d86dc588ea7e4d67e1d4cf587c909f7f 100644 (file)
@@ -479,6 +479,28 @@ type TstX struct {
        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 @@ func TestCheckCondition(t *testing.T) {
        }{
                {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}},