From f28d8b8601ab11bed8750b2222d02544b5d83291 Mon Sep 17 00:00:00 2001 From: Craig Peterson Date: Sat, 26 Mar 2016 13:07:35 -0600 Subject: [PATCH] Adding some useful utility functions for templates --- middleware/context.go | 38 ++++++++++++++++++++++++++++++++++++++ middleware/context_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/middleware/context.go b/middleware/context.go index ea63d3e2..3facb953 100644 --- a/middleware/context.go +++ b/middleware/context.go @@ -2,6 +2,7 @@ package middleware import ( "bytes" + "fmt" "io/ioutil" "net" "net/http" @@ -219,3 +220,40 @@ func ContextInclude(filename string, ctx interface{}, fs http.FileSystem) (strin return buf.String(), nil } + +// ToLower will convert the given string to lower case. +func (c Context) ToLower(s string) string { + return strings.ToLower(s) +} + +// ToUpper will convert the given string to upper case. +func (c Context) ToUpper(s string) string { + return strings.ToUpper(s) +} + +// Split is a passthrough to strings.Split. It will split the first argument at each instance of the seperator and return a slice of strings. +func (c Context) Split(s string, sep string) []string { + return strings.Split(s, sep) +} + +// Slice will convert the given arguments into a slice. +func (c Context) Slice(elems ...interface{}) []interface{} { + return elems +} + +// Map will convert the arguments into a map. It expects alternating string keys and values. This is useful for building more complicated data structures +// if you are using subtemplates or things like that. +func (c Context) Map(values ...interface{}) (map[string]interface{}, error) { + if len(values)%2 != 0 { + return nil, fmt.Errorf("Map expects an even number of arguments") + } + dict := make(map[string]interface{}, len(values)/2) + for i := 0; i < len(values); i += 2 { + key, ok := values[i].(string) + if !ok { + return nil, fmt.Errorf("Map keys must be strings") + } + dict[key] = values[i+1] + } + return dict, nil +} diff --git a/middleware/context_test.go b/middleware/context_test.go index 689c47c1..e0c91f64 100644 --- a/middleware/context_test.go +++ b/middleware/context_test.go @@ -11,6 +11,8 @@ import ( "strings" "testing" "time" + + "text/template" ) func TestInclude(t *testing.T) { @@ -611,3 +613,32 @@ func getContextOrFail(t *testing.T) Context { func getTestPrefix(testN int) string { return fmt.Sprintf("Test [%d]: ", testN) } + +func TestTemplates(t *testing.T) { + tests := []struct{ tmpl, expected string }{ + {`{{.ToUpper "aAA"}}`, "AAA"}, + {`{{"bbb" | .ToUpper}}`, "BBB"}, + {`{{.ToLower "CCc"}}`, "ccc"}, + {`{{range (.Split "a,b,c" ",")}}{{.}}{{end}}`, "abc"}, + {`{{range .Split "a,b,c" ","}}{{.}}{{end}}`, "abc"}, + {`{{range .Slice "a" "b" "c"}}{{.}}{{end}}`, "abc"}, + {`{{with .Map "A" "a" "B" "b" "c" "d"}}{{.A}}{{.B}}{{.c}}{{end}}`, "abd"}, + } + for i, test := range tests { + ctx := getContextOrFail(t) + tmpl, err := template.New("").Parse(test.tmpl) + if err != nil { + t.Errorf("Test %d: %s", i, err) + continue + } + buf := &bytes.Buffer{} + err = tmpl.Execute(buf, ctx) + if err != nil { + t.Errorf("Test %d: %s", i, err) + continue + } + if buf.String() != test.expected { + t.Errorf("Test %d: Results do not match. '%s' != '%s'", i, buf.String(), test.expected) + } + } +}