ref: ce9ee3cf490ab5485b6ad7aa7a47d9fa9d176fa3
parent: 0962470850ed6802b645d5bd6663db60807c8f5b
author: Cameron Moore <[email protected]>
date: Wed Mar 9 09:40:00 EST 2016
tpl: Add default function
--- a/docs/content/templates/functions.md
+++ b/docs/content/templates/functions.md
@@ -28,6 +28,17 @@
## General
+### default
+Checks whether a given value is set and returns a default value if it 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.
+
+e.g.
+
+ {{ .Params.font | default "Roboto" }} → default is "Roboto"
+ {{ default "Roboto" .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.
Maps will be sorted by the keys, and only a slice of the values will be returned, keeping a consistent output order.
--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -1239,6 +1239,44 @@
return t.Format(layout), nil
}
+// dfault checks whether a given value is set and returns a default value if it
+// 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)
+ if !g.IsValid() {
+ return dflt
+ }
+
+ set := false
+
+ switch g.Kind() {
+ case reflect.Bool:
+ set = g.Bool()
+ case reflect.String, reflect.Array, reflect.Slice, reflect.Map:
+ set = g.Len() != 0
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ set = g.Int() != 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ set = g.Uint() != 0
+ case reflect.Float32, reflect.Float64:
+ set = g.Float() != 0
+ case reflect.Complex64, reflect.Complex128:
+ set = g.Complex() != 0
+ case reflect.Struct:
+ set = true
+ default:
+ set = !g.IsNil()
+ }
+
+ if set {
+ return given
+ }
+
+ return dflt
+}
+
// safeHTMLAttr returns a given string as html/template HTMLAttr content.
//
// safeHTMLAttr is currently disabled, pending further discussion
@@ -1537,6 +1575,7 @@
"chomp": chomp,
"countrunes": countRunes,
"countwords": countWords,
+ "default": dfault,
"dateFormat": dateFormat,
"delimit": delimit,
"dict": dictionary,
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -18,9 +18,6 @@
"encoding/base64"
"errors"
"fmt"
- "github.com/spf13/cast"
- "github.com/spf13/viper"
- "github.com/stretchr/testify/assert"
"html/template"
"math/rand"
"path"
@@ -29,6 +26,10 @@
"strings"
"testing"
"time"
+
+ "github.com/spf13/cast"
+ "github.com/spf13/viper"
+ "github.com/stretchr/testify/assert"
)
type tstNoStringer struct {
@@ -1839,6 +1840,44 @@
if result != this.expect {
t.Errorf("[%d] DateFormat got %v but expected %v", i, result, this.expect)
}
+ }
+ }
+}
+
+func TestDefault(t *testing.T) {
+ for i, this := range []struct {
+ dflt interface{}
+ given interface{}
+ expected interface{}
+ }{
+ {"5", 0, "5"},
+
+ {"test1", "set", "set"},
+ {"test2", "", "test2"},
+
+ {[2]int{10, 20}, [2]int{1, 2}, [2]int{1, 2}},
+ {[2]int{10, 20}, [0]int{}, [2]int{10, 20}},
+
+ {[]string{"one"}, []string{"uno"}, []string{"uno"}},
+ {[]string{"one"}, []string{}, []string{"one"}},
+
+ {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}},
+
+ {10, 1, 1},
+ {10, 0, 10},
+
+ {float32(10), float32(1), float32(1)},
+ {float32(10), 0, float32(10)},
+
+ {complex(2, -2), complex(1, -1), complex(1, -1)},
+ {complex(2, -2), complex(0, 0), complex(2, -2)},
+
+ {struct{ f string }{f: "one"}, struct{ f string }{}, struct{ f string }{}},
+ } {
+ res := dfault(this.dflt, this.given)
+ if !reflect.DeepEqual(this.expected, res) {
+ t.Errorf("[%d] default returned %v, but expected %v", i, res, this.expected)
}
}
}