From 8ad9c0a7dd26513dd597040276ac34bf00830813 Mon Sep 17 00:00:00 2001 From: bep Date: Wed, 5 Nov 2014 18:45:02 +0100 Subject: [PATCH] Make Where template-method accept methodname as key This is necessary to make constructs like `{{ range first 1 (where .Data.Pages "Type" "post") }}` -- as Type and Section is methods not fields. --- hugolib/template.go | 18 ++++++++++++++---- hugolib/template_test.go | 28 +++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/hugolib/template.go b/hugolib/template.go index 2de1396f7..9509d8ea2 100644 --- a/hugolib/template.go +++ b/hugolib/template.go @@ -230,8 +230,13 @@ func Where(seq, key, match interface{}) (interface{}, error) { vvv = vv.MapIndex(kv) } case reflect.Struct: - if kv.Kind() == reflect.String && vv.FieldByName(kv.String()).IsValid() { - vvv = vv.FieldByName(kv.String()) + if kv.Kind() == reflect.String { + method := vv.MethodByName(kv.String()) + if method.IsValid() && method.Type().NumIn() == 0 && method.Type().NumOut() > 0 { + vvv = method.Call(nil)[0] + } else if vv.FieldByName(kv.String()).IsValid() { + vvv = vv.FieldByName(kv.String()) + } } case reflect.Ptr: if !vv.IsNil() { @@ -242,8 +247,13 @@ func Where(seq, key, match interface{}) (interface{}, error) { vvv = ev.MapIndex(kv) } case reflect.Struct: - if kv.Kind() == reflect.String && ev.FieldByName(kv.String()).IsValid() { - vvv = ev.FieldByName(kv.String()) + if kv.Kind() == reflect.String { + method := vv.MethodByName(kv.String()) + if method.IsValid() && method.Type().NumIn() == 0 && method.Type().NumOut() > 0 { + vvv = method.Call(nil)[0] + } else if ev.FieldByName(kv.String()).IsValid() { + vvv = ev.FieldByName(kv.String()) + } } } } diff --git a/hugolib/template_test.go b/hugolib/template_test.go index a573f1125..0e437387e 100644 --- a/hugolib/template_test.go +++ b/hugolib/template_test.go @@ -1,6 +1,7 @@ package hugolib import ( + "github.com/spf13/hugo/source" "reflect" "testing" ) @@ -296,10 +297,23 @@ func TestIntersect(t *testing.T) { } } +func (x *TstX) TstRp() string { + return "r" + x.A +} + +func (x TstX) TstRv() string { + return "r" + x.B +} + +type TstX struct { + A, B string +} + func TestWhere(t *testing.T) { - type X struct { - A, B string - } + + page1 := &Page{contentType: "v", Source: Source{File: *source.NewFile("/x/y/z/source.md")}} + page2 := &Page{contentType: "w", Source: Source{File: *source.NewFile("/y/z/a/source.md")}} + for i, this := range []struct { sequence interface{} key interface{} @@ -308,9 +322,13 @@ func TestWhere(t *testing.T) { }{ {[]map[int]string{{1: "a", 2: "m"}, {1: "c", 2: "d"}, {1: "e", 3: "m"}}, 2, "m", []map[int]string{{1: "a", 2: "m"}}}, {[]map[string]int{{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4}}, "b", 4, []map[string]int{{"a": 3, "b": 4}}}, - {[]X{{"a", "b"}, {"c", "d"}, {"e", "f"}}, "B", "f", []X{{"e", "f"}}}, + {[]TstX{{"a", "b"}, {"c", "d"}, {"e", "f"}}, "B", "f", []TstX{{"e", "f"}}}, {[]*map[int]string{&map[int]string{1: "a", 2: "m"}, &map[int]string{1: "c", 2: "d"}, &map[int]string{1: "e", 3: "m"}}, 2, "m", []*map[int]string{&map[int]string{1: "a", 2: "m"}}}, - {[]*X{&X{"a", "b"}, &X{"c", "d"}, &X{"e", "f"}}, "B", "f", []*X{&X{"e", "f"}}}, + {[]*TstX{&TstX{"a", "b"}, &TstX{"c", "d"}, &TstX{"e", "f"}}, "B", "f", []*TstX{&TstX{"e", "f"}}}, + {[]*TstX{&TstX{"a", "b"}, &TstX{"c", "d"}, &TstX{"e", "c"}}, "TstRp", "rc", []*TstX{&TstX{"c", "d"}}}, + {[]TstX{TstX{"a", "b"}, TstX{"c", "d"}, TstX{"e", "c"}}, "TstRv", "rc", []TstX{TstX{"e", "c"}}}, + {[]*Page{page1, page2}, "Type", "v", []*Page{page1}}, + {[]*Page{page1, page2}, "Section", "y", []*Page{page2}}, } { results, err := Where(this.sequence, this.key, this.match) if err != nil {