URI: 
       Implement substr template function - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit 5b0245ca59e22d90add28b11898ecfd602429e43
   DIR parent beb423a2d9683dfc07b2f69766e17c32589d489b
  HTML Author: Anthony Fok <foka@debian.org>
       Date:   Mon, 23 Mar 2015 11:23:13 -0600
       
       Implement substr template function
       
       Its behavior is similar to that in JavaScript
       with special handling of negative length as found in in PHP.
       
       Fixes #991
       
       Diffstat:
         M tpl/template.go                     |      64 +++++++++++++++++++++++++++++++
         M tpl/template_test.go                |      40 +++++++++++++++++++++++++++++++
       
       2 files changed, 104 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/tpl/template.go b/tpl/template.go
       @@ -210,6 +210,69 @@ func Slicestr(a interface{}, start, end int) (string, error) {
        
        }
        
       +// Substr extracts parts of a string, beginning at the character at the specified
       +// position, and returns the specified number of characters.
       +//
       +// It normally takes two parameters: start and length.
       +// It can also take one parameter: start, i.e. length is omitted, in which case
       +// the substring starting from start until the end of the string will be returned.
       +//
       +// To extract characters from the end of the string, use a negative start number.
       +//
       +// In addition, borrowing from the extended behavior described at http://php.net/substr,
       +// if length is given and is negative, then that many characters will be omitted from
       +// the end of string.
       +func Substr(a interface{}, nums ...int) (string, error) {
       +        aStr, err := cast.ToStringE(a)
       +        if err != nil {
       +                return "", err
       +        }
       +
       +        var start, length int
       +        switch len(nums) {
       +        case 1:
       +                start = nums[0]
       +                length = len(aStr)
       +        case 2:
       +                start = nums[0]
       +                length = nums[1]
       +        default:
       +                return "", errors.New("too many arguments")
       +        }
       +
       +        if start < -len(aStr) {
       +                start = 0
       +        }
       +        if start > len(aStr) {
       +                return "", errors.New(fmt.Sprintf("start position out of bounds for %d-byte string", len(aStr)))
       +        }
       +
       +        var s, e int
       +        if start >= 0 && length >= 0 {
       +                s = start
       +                e = start + length
       +        } else if start < 0 && length >= 0 {
       +                s = len(aStr) + start - length + 1
       +                e = len(aStr) + start + 1
       +        } else if start >= 0 && length < 0 {
       +                s = start
       +                e = len(aStr) + length
       +        } else {
       +                s = len(aStr) + start
       +                e = len(aStr) + length
       +        }
       +
       +        if s > e {
       +                return "", errors.New(fmt.Sprintf("calculated start position greater than end position: %d > %d", s, e))
       +        }
       +        if e > len(aStr) {
       +                e = len(aStr)
       +        }
       +
       +        return aStr[s:e], nil
       +
       +}
       +
        func Split(a interface{}, delimiter string) ([]string, error) {
                aStr, err := cast.ToStringE(a)
                if err != nil {
       @@ -1339,6 +1402,7 @@ func init() {
                        "le":          Le,
                        "in":          In,
                        "slicestr":    Slicestr,
       +                "substr":      Substr,
                        "split":       Split,
                        "intersect":   Intersect,
                        "isSet":       IsSet,
   DIR diff --git a/tpl/template_test.go b/tpl/template_test.go
       @@ -310,6 +310,46 @@ func TestSlicestr(t *testing.T) {
                }
        }
        
       +func TestSubstr(t *testing.T) {
       +        for i, this := range []struct {
       +                v1     interface{}
       +                v2     int
       +                v3     int
       +                expect interface{}
       +        }{
       +                {"abc", 1, 2, "bc"},
       +                {"abc", 0, 1, "a"},
       +                {"abcdef", -1, 2, "ef"},
       +                {"abcdef", -3, 3, "bcd"},
       +                {"abcdef", 0, -1, "abcde"},
       +                {"abcdef", 2, -1, "cde"},
       +                {"abcdef", 4, -4, false},
       +                {"abcdef", 7, 1, false},
       +                {"abcdef", 1, 100, "bcdef"},
       +                {"abcdef", -100, 3, "abc"},
       +                {"abcdef", -3, -1, "de"},
       +                {123, 1, 3, "23"},
       +                {1.2e3, 0, 4, "1200"},
       +                {tstNoStringer{}, 0, 1, false},
       +        } {
       +                result, err := Substr(this.v1, this.v2, this.v3)
       +
       +                if b, ok := this.expect.(bool); ok && !b {
       +                        if err == nil {
       +                                t.Errorf("[%d] Substr didn't return an expected error", i)
       +                        }
       +                } else {
       +                        if err != nil {
       +                                t.Errorf("[%d] failed: %s", i, err)
       +                                continue
       +                        }
       +                        if !reflect.DeepEqual(result, this.expect) {
       +                                t.Errorf("[%d] Got %s but expected %s", i, result, this.expect)
       +                        }
       +                }
       +        }
       +}
       +
        func TestSplit(t *testing.T) {
                for i, this := range []struct {
                        v1     interface{}