From 5b51b3b9fb19d8d20e99d3c249c0052793abe50a Mon Sep 17 00:00:00 2001 From: Benny Wu Date: Fri, 14 Aug 2015 15:36:56 +0700 Subject: [PATCH] Slicestr fix for other int type param Fixes #1347 --- tpl/template_funcs.go | 65 ++++++++++++++++++++++++-------------- tpl/template_funcs_test.go | 53 ++++++++++++++++++++----------- 2 files changed, 76 insertions(+), 42 deletions(-) diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go index d26dc6494..4b9f70111 100644 --- a/tpl/template_funcs.go +++ b/tpl/template_funcs.go @@ -128,32 +128,65 @@ func compareGetFloat(a interface{}, b interface{}) (float64, float64) { return left, right } +// Taken out from Substr, to be used by Slicestr too. +func toInt(v interface{}, message string) (int, error) { + switch i := v.(type) { + case int: + return i, nil + case int8: + return int(i), nil + case int16: + return int(i), nil + case int32: + return int(i), nil + case int64: + return int(i), nil + default: + return 0, errors.New(message) + } +} + // Slicing in Slicestr is done by specifying a half-open range with // two indices, start and end. 1 and 4 creates a slice including elements 1 through 3. // The end index can be omitted, it defaults to the string's length. -func Slicestr(a interface{}, startEnd ...int) (string, error) { +func Slicestr(a interface{}, startEnd ...interface{}) (string, error) { aStr, err := cast.ToStringE(a) if err != nil { return "", err } - if len(startEnd) > 2 { + var argStart, argEnd int + + argNum := len(startEnd) + + if argNum > 0 { + if argStart, err = toInt(startEnd[0], "start argument must be integer"); err != nil { + return "", err + } + } + if argNum > 1 { + if argEnd, err = toInt(startEnd[1], "end argument must be integer"); err != nil { + return "", err + } + } + + if argNum > 2 { return "", errors.New("too many arguments") } asRunes := []rune(aStr) - if len(startEnd) > 0 && (startEnd[0] < 0 || startEnd[0] >= len(asRunes)) { + if argNum > 0 && (argStart < 0 || argStart >= len(asRunes)) { return "", errors.New("slice bounds out of range") } - if len(startEnd) == 2 { - if startEnd[1] < 0 || startEnd[1] > len(asRunes) { + if argNum == 2 { + if argEnd < 0 || argEnd > len(asRunes) { return "", errors.New("slice bounds out of range") } - return string(asRunes[startEnd[0]:startEnd[1]]), nil - } else if len(startEnd) == 1 { - return string(asRunes[startEnd[0]:]), nil + return string(asRunes[argStart:argEnd]), nil + } else if argNum == 1 { + return string(asRunes[argStart:]), nil } else { return string(asRunes[:]), nil } @@ -179,22 +212,6 @@ func Substr(a interface{}, nums ...interface{}) (string, error) { } var start, length int - toInt := func(v interface{}, message string) (int, error) { - switch i := v.(type) { - case int: - return i, nil - case int8: - return int(i), nil - case int16: - return int(i), nil - case int32: - return int(i), nil - case int64: - return int(i), nil - default: - return 0, errors.New(message) - } - } asRunes := []rune(aStr) diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go index d86eeba1c..585702ae7 100644 --- a/tpl/template_funcs_test.go +++ b/tpl/template_funcs_test.go @@ -348,29 +348,46 @@ func TestIn(t *testing.T) { } func TestSlicestr(t *testing.T) { + var err error for i, this := range []struct { v1 interface{} - v2 []int + v2 interface{} + v3 interface{} expect interface{} }{ - {"abc", []int{1, 2}, "b"}, - {"abc", []int{1, 3}, "bc"}, - {"abc", []int{0, 1}, "a"}, - {"abcdef", []int{}, "abcdef"}, - {"abcdef", []int{0, 6}, "abcdef"}, - {"abcdef", []int{0, 2}, "ab"}, - {"abcdef", []int{2}, "cdef"}, - {123, []int{1, 3}, "23"}, - {123, []int{1, 2, 3}, false}, - {"abcdef", []int{6}, false}, - {"abcdef", []int{4, 7}, false}, - {"abcdef", []int{-1}, false}, - {"abcdef", []int{-1, 7}, false}, - {"abcdef", []int{1, -1}, false}, - {tstNoStringer{}, []int{0, 1}, false}, - {"ĀĀĀ", []int{0, 1}, "Ā"}, // issue #1333 + {"abc", 1, 2, "b"}, + {"abc", 1, 3, "bc"}, + {"abcdef", 1, int8(3), "bc"}, + {"abcdef", 1, int16(3), "bc"}, + {"abcdef", 1, int32(3), "bc"}, + {"abcdef", 1, int64(3), "bc"}, + {"abc", 0, 1, "a"}, + {"abcdef", nil, nil, "abcdef"}, + {"abcdef", 0, 6, "abcdef"}, + {"abcdef", 0, 2, "ab"}, + {"abcdef", 2, nil, "cdef"}, + {"abcdef", int8(2), nil, "cdef"}, + {"abcdef", int16(2), nil, "cdef"}, + {"abcdef", int32(2), nil, "cdef"}, + {"abcdef", int64(2), nil, "cdef"}, + {123, 1, 3, "23"}, + {"abcdef", 6, nil, false}, + {"abcdef", 4, 7, false}, + {"abcdef", -1, nil, false}, + {"abcdef", -1, 7, false}, + {"abcdef", 1, -1, false}, + {tstNoStringer{}, 0, 1, false}, + {"ĀĀĀ", 0, 1, "Ā"}, // issue #1333 } { - result, err := Slicestr(this.v1, this.v2...) + + var result string + if this.v2 == nil { + result, err = Slicestr(this.v1) + } else if this.v3 == nil { + result, err = Slicestr(this.v1, this.v2) + } else { + result, err = Slicestr(this.v1, this.v2, this.v3) + } if b, ok := this.expect.(bool); ok && !b { if err == nil {