diff options
author | Austin Ziegler <austin@zieglers.ca> | 2014-12-10 06:46:33 +0300 |
---|---|---|
committer | bep <bjorn.erik.pedersen@gmail.com> | 2015-01-02 13:50:22 +0300 |
commit | ae9c25afc078677500478e2a948502e7e1ed4830 (patch) | |
tree | cdf3f56ae12d71945985317022374389c6ac0f19 /tpl | |
parent | 6033abe1e7f69a8539137cc2659624866e2e1183 (diff) |
Implement `apply`.
- apply seq fn argsā¦
Diffstat (limited to 'tpl')
-rw-r--r-- | tpl/template.go | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/tpl/template.go b/tpl/template.go index ef0096cef..a116c2136 100644 --- a/tpl/template.go +++ b/tpl/template.go @@ -422,6 +422,68 @@ func Where(seq, key, match interface{}) (r interface{}, err error) { } } +func Apply(seq interface{}, fname string, args ...interface{}) (interface{}, error) { + if seq == nil { + return make([]interface{}, 0), nil + } + + if fname == "apply" { + return nil, errors.New("can't apply myself (no turtles allowed)") + } + + seqv := reflect.ValueOf(seq) + seqv, isNil := indirect(seqv) + if isNil { + return nil, errors.New("can't iterate over a nil value") + } + + fn, found := funcMap[fname] + if !found { + return nil, errors.New("can't find function " + fname) + } + + fnv := reflect.ValueOf(fn) + + switch seqv.Kind() { + case reflect.Array, reflect.Slice: + r := make([]interface{}, seqv.Len()) + for i := 0; i < seqv.Len(); i++ { + vv := seqv.Index(i) + + vvv, err := applyFnToThis(fnv, vv, args...) + + if err != nil { + return nil, err + } + + r[i] = vvv.Interface() + } + + return r, nil + default: + return nil, errors.New("can't apply over " + reflect.ValueOf(seq).Type().String()) + } +} + +func applyFnToThis(fn, this reflect.Value, args ...interface{}) (reflect.Value, error) { + n := make([]reflect.Value, len(args)) + for i, arg := range args { + if arg == "." { + n[i] = this + } else { + n[i] = reflect.ValueOf(arg) + } + } + + res := fn.Call(n) + + if len(res) == 1 || res[1].IsNil() { + return res[0], nil + } else { + return reflect.ValueOf(nil), res[1].Interface().(error) + } +} + func Delimit(seq, delimiter interface{}, last ...interface{}) (template.HTML, error) { d, err := cast.ToStringE(delimiter) if err != nil { @@ -1033,6 +1095,7 @@ func init() { "partial": Partial, "ref": Ref, "relref": RelRef, + "apply": Apply, "chomp": Chomp, } |