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.
This commit is contained in:
bep 2014-11-05 18:45:02 +01:00 committed by spf13
parent fdae09070b
commit 8ad9c0a7dd
2 changed files with 37 additions and 9 deletions

View file

@ -230,9 +230,14 @@ func Where(seq, key, match interface{}) (interface{}, error) {
vvv = vv.MapIndex(kv) vvv = vv.MapIndex(kv)
} }
case reflect.Struct: case reflect.Struct:
if kv.Kind() == reflect.String && vv.FieldByName(kv.String()).IsValid() { 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()) vvv = vv.FieldByName(kv.String())
} }
}
case reflect.Ptr: case reflect.Ptr:
if !vv.IsNil() { if !vv.IsNil() {
ev := vv.Elem() ev := vv.Elem()
@ -242,12 +247,17 @@ func Where(seq, key, match interface{}) (interface{}, error) {
vvv = ev.MapIndex(kv) vvv = ev.MapIndex(kv)
} }
case reflect.Struct: case reflect.Struct:
if kv.Kind() == reflect.String && ev.FieldByName(kv.String()).IsValid() { 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()) vvv = ev.FieldByName(kv.String())
} }
} }
} }
} }
}
if vvv.IsValid() && mv.Type() == vvv.Type() { if vvv.IsValid() && mv.Type() == vvv.Type() {
switch mv.Kind() { switch mv.Kind() {

View file

@ -1,6 +1,7 @@
package hugolib package hugolib
import ( import (
"github.com/spf13/hugo/source"
"reflect" "reflect"
"testing" "testing"
) )
@ -296,10 +297,23 @@ func TestIntersect(t *testing.T) {
} }
} }
func TestWhere(t *testing.T) { func (x *TstX) TstRp() string {
type X struct { return "r" + x.A
}
func (x TstX) TstRv() string {
return "r" + x.B
}
type TstX struct {
A, B string A, B string
} }
func TestWhere(t *testing.T) {
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 { for i, this := range []struct {
sequence interface{} sequence interface{}
key 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[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}}}, {[]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"}}}, {[]*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) results, err := Where(this.sequence, this.key, this.match)
if err != nil { if err != nil {