ref: 09c8c17bf06ed5f215922b0755558e58a8723802
parent: 0743646f3232b55b4df2690cbb11682794884243
author: Cameron Moore <moorereason@gmail.com>
date: Wed Mar 9 11:27:56 EST 2016
tpl: fix default function This commit fixes a few things: 1. `given` is now a variadic parameter so that piping works properly 2. add separate template tests to make sure piping works 3. support time values 4. add more tests of the dfault function
--- a/docs/content/templates/functions.md
+++ b/docs/content/templates/functions.md
@@ -37,7 +37,7 @@
e.g.
{{ index .Params "font" | default "Roboto" }} → default is "Roboto"- {{ default "Roboto" .Params.font }} → default is "Roboto"+ {{ default "Roboto" (index .Params "font") }} → default is "Roboto"### delimit
Loops through any array, slice or map and returns a string of all the values separated by the delimiter. There is an optional third parameter that lets you choose a different delimiter to go between the last two values.
--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -1243,10 +1243,21 @@
// is not. "Set" in this context means true for booleans; non-zero for numeric
// types; non-zero length for strings, arrays, slices, and maps; any struct
// value; or non-nil for any other types.
-func dfault(dflt, given interface{}) interface{} {- g := reflect.ValueOf(given)
+func dfault(dflt interface{}, given ...interface{}) (interface{}, error) {+ // given is variadic because the following construct will not pass a piped
+ // argument when the key is missing: {{ index . "key" | default "foo" }}+ // The Go template will complain that we got 1 argument when we expectd 2.
+
+ if given == nil || len(given) == 0 {+ return dflt, nil
+ }
+ if len(given) != 1 {+ return nil, fmt.Errorf("wrong number of args for default: want 2 got %d", len(given)+1)+ }
+
+ g := reflect.ValueOf(given[0])
if !g.IsValid() {- return dflt
+ return dflt, nil
}
set := false
@@ -1265,16 +1276,21 @@
case reflect.Complex64, reflect.Complex128:
set = g.Complex() != 0
case reflect.Struct:
- set = true
+ switch actual := given[0].(type) {+ case time.Time:
+ set = !actual.IsZero()
+ default:
+ set = true
+ }
default:
set = !g.IsNil()
}
if set {- return given
+ return given[0], nil
}
- return dflt
+ return dflt, nil
}
// safeHTMLAttr returns a given string as html/template HTMLAttr content.
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -1844,7 +1844,10 @@
}
}
-func TestDefault(t *testing.T) {+func TestDefaultFunc(t *testing.T) {+ then := time.Now()
+ now := time.Now()
+
for i, this := range []struct { dflt interface{} given interface{}@@ -1854,30 +1857,76 @@
{"test1", "set", "set"}, {"test2", "", "test2"},+ {"test3", nil, "test3"}, {[2]int{10, 20}, [2]int{1, 2}, [2]int{1, 2}}, {[2]int{10, 20}, [0]int{}, [2]int{10, 20}},+ {[2]int{100, 200}, nil, [2]int{100, 200}}, {[]string{"one"}, []string{"uno"}, []string{"uno"}},- {[]string{"one"}, []string{}, []string{"one"}},+ {[]string{"two"}, []string{}, []string{"two"}},+ {[]string{"three"}, nil, []string{"three"}}, {map[string]int{"one": 1}, map[string]int{"uno": 1}, map[string]int{"uno": 1}}, {map[string]int{"one": 1}, map[string]int{}, map[string]int{"one": 1}},+ {map[string]int{"two": 2}, nil, map[string]int{"two": 2}}, {10, 1, 1}, {10, 0, 10},+ {20, nil, 20}, {float32(10), float32(1), float32(1)}, {float32(10), 0, float32(10)},+ {float32(20), nil, float32(20)}, {complex(2, -2), complex(1, -1), complex(1, -1)}, {complex(2, -2), complex(0, 0), complex(2, -2)},+ {complex(3, -3), nil, complex(3, -3)}, {struct{ f string }{f: "one"}, struct{ f string }{}, struct{ f string }{}},+ {struct{ f string }{f: "two"}, nil, struct{ f string }{f: "two"}},+
+ {then, now, now},+ {then, time.Time{}, then}, } {- res := dfault(this.dflt, this.given)
+ res, err := dfault(this.dflt, this.given)
+ if err != nil {+ t.Errorf("[%d] default returned an error: %s", i, err)+ continue
+ }
if !reflect.DeepEqual(this.expected, res) { t.Errorf("[%d] default returned %v, but expected %v", i, res, this.expected)+ }
+ }
+}
+
+func TestDefault(t *testing.T) {+ for i, this := range []struct {+ input interface{}+ tpl string
+ expected string
+ ok bool
+ }{+ {map[string]string{"foo": "bar"}, `{{ index . "foo" | default "nope" }}`, `bar`, true},+ {map[string]string{"foo": "pop"}, `{{ index . "bar" | default "nada" }}`, `nada`, true},+ {map[string]string{"foo": "cat"}, `{{ default "nope" .foo }}`, `cat`, true},+ {map[string]string{"foo": "dog"}, `{{ default "nope" .foo "extra" }}`, ``, false},+ } {+ tmpl, err := New().New("test").Parse(this.tpl)+ if err != nil {+ t.Errorf("[%d] unable to create new html template %q: %s", i, this.tpl, err)+ continue
+ }
+
+ buf := new(bytes.Buffer)
+ err = tmpl.Execute(buf, this.input)
+ if (err == nil) != this.ok {+ t.Errorf("[%d] execute template returned unexpected error: %s", i, err)+ continue
+ }
+
+ if buf.String() != this.expected {+ t.Errorf("[%d] execute template got %v, but expected %v", i, buf.String(), this.expected)}
}
}
--
⑨