Add `last` template function - hugo - [fork] hugo port for 9front
 (HTM) git clone git@git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 0a2e5424ab5b684e88eebe87efc88c55e11e9789
 (DIR) parent 627d016cc95d355f54e9565c44bfef419e0c7044
 (HTM) Author: Ariejan de Vroom <ariejan@ariejan.net>
       Date:   Thu, 11 Jun 2015 00:11:47 +0200
       
       Add `last` template function
       
       `last` allows the user to select the last X items of
       and array.
       
       Diffstat:
         M tpl/template_funcs.go               |      37 +++++++++++++++++++++++++++++++
         M tpl/template_funcs_test.go          |      34 +++++++++++++++++++++++++++++++
       
       2 files changed, 71 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go
       @@ -388,6 +388,42 @@ func First(limit interface{}, seq interface{}) (interface{}, error) {
                return seqv.Slice(0, limitv).Interface(), nil
        }
        
       +// Last is exposed to templates, to iterate over the last N items in a
       +// rangeable list.
       +func Last(limit interface{}, seq interface{}) (interface{}, error) {
       +
       +        if limit == nil || seq == nil {
       +                return nil, errors.New("both limit and seq must be provided")
       +        }
       +
       +        limitv, err := cast.ToIntE(limit)
       +
       +        if err != nil {
       +                return nil, err
       +        }
       +
       +        if limitv < 1 {
       +                return nil, errors.New("can't return negative/empty count of items from sequence")
       +        }
       +
       +        seqv := reflect.ValueOf(seq)
       +        seqv, isNil := indirect(seqv)
       +        if isNil {
       +                return nil, errors.New("can't iterate over a nil value")
       +        }
       +
       +        switch seqv.Kind() {
       +        case reflect.Array, reflect.Slice, reflect.String:
       +                // okay
       +        default:
       +                return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
       +        }
       +        if limitv > seqv.Len() {
       +                limitv = seqv.Len()
       +        }
       +        return seqv.Slice(seqv.Len()-limitv, seqv.Len()).Interface(), nil
       +}
       +
        // After is exposed to templates, to iterate over all the items after N in a
        // rangeable list. It's meant to accompany First
        func After(index interface{}, seq interface{}) (interface{}, error) {
       @@ -1288,6 +1324,7 @@ func init() {
                        "relURL":      func(a string) template.HTML { return template.HTML(helpers.RelURL(a)) },
                        "markdownify": Markdownify,
                        "first":       First,
       +                "last":        Last,
                        "after":       After,
                        "where":       Where,
                        "delimit":     Delimit,
 (DIR) diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go
       @@ -253,6 +253,40 @@ func TestFirst(t *testing.T) {
                }
        }
        
       +func TestLast(t *testing.T) {
       +        for i, this := range []struct {
       +                count    interface{}
       +                sequence interface{}
       +                expect   interface{}
       +        }{
       +                {int(2), []string{"a", "b", "c"}, []string{"b", "c"}},
       +                {int32(3), []string{"a", "b"}, []string{"a", "b"}},
       +                {int64(2), []int{100, 200, 300}, []int{200, 300}},
       +                {100, []int{100, 200}, []int{100, 200}},
       +                {"1", []int{100, 200, 300}, []int{300}},
       +                {int64(-1), []int{100, 200, 300}, false},
       +                {"noint", []int{100, 200, 300}, false},
       +                {1, nil, false},
       +                {nil, []int{100}, false},
       +                {1, t, false},
       +        } {
       +                results, err := Last(this.count, this.sequence)
       +                if b, ok := this.expect.(bool); ok && !b {
       +                        if err == nil {
       +                                t.Errorf("[%d] First didn't return an expected error", i)
       +                        }
       +                } else {
       +                        if err != nil {
       +                                t.Errorf("[%d] failed: %s", i, err)
       +                                continue
       +                        }
       +                        if !reflect.DeepEqual(results, this.expect) {
       +                                t.Errorf("[%d] First %d items, got %v but expected %v", i, this.count, results, this.expect)
       +                        }
       +                }
       +        }
       +}
       +
        func TestAfter(t *testing.T) {
                for i, this := range []struct {
                        count    interface{}