tpl: Add default function

This commit is contained in:
Cameron Moore 2016-03-09 14:40:00 -06:00 committed by Bjørn Erik Pedersen
parent 0962470850
commit ce9ee3cf49
3 changed files with 92 additions and 3 deletions

View file

@ -28,6 +28,17 @@ and other basic tools; these are listed in the
## 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.

View file

@ -1239,6 +1239,44 @@ func dateFormat(layout string, v interface{}) (string, error) {
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 @@ func init() {
"chomp": chomp,
"countrunes": countRunes,
"countwords": countWords,
"default": dfault,
"dateFormat": dateFormat,
"delimit": delimit,
"dict": dictionary,

View file

@ -18,9 +18,6 @@ import (
"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 @@ import (
"strings"
"testing"
"time"
"github.com/spf13/cast"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
)
type tstNoStringer struct {
@ -1843,6 +1844,44 @@ func TestDateFormat(t *testing.T) {
}
}
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)
}
}
}
func TestSafeHTML(t *testing.T) {
for i, this := range []struct {
str string