Skip to content

Commit

Permalink
Deprecate most of "templatelib" in favor of Sprig
Browse files Browse the repository at this point in the history
It implements many of the same functions like `first`, `last`, `ternary`, etc, some just with a different name like `toJson` vs `json`, and gives us *many* more useful functions.
  • Loading branch information
tianon committed Dec 22, 2020
1 parent 8e42901 commit be75a74
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 52 deletions.
2 changes: 1 addition & 1 deletion cmd/bashbrew/cmd-cat.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func cmdCat(c *cli.Context) error {
}

var i int
tmpl, err := template.New(templateName).Funcs(templatelib.FuncMap).Funcs(template.FuncMap{
tmpl, err := template.New(templateName).Funcs(templatelib.FuncMap()).Funcs(template.FuncMap{
"i": func() int {
return i
},
Expand Down
69 changes: 28 additions & 41 deletions pkg/templatelib/lib.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package templatelib

import (
"encoding/json"
"fmt"
"os"
"reflect"
"strings"
"text/template"

"github.com/Masterminds/sprig/v3"
)

func swapStringsFuncBoolArgsOrder(a func(string, string) bool) func(string, string) bool {
Expand Down Expand Up @@ -68,55 +69,33 @@ func stringsModifierActionFactory(a func(string, string) string) func([]string,
}
}

var FuncMap = template.FuncMap{
// {{- $isGitHub := hasPrefix "https://github.com/" $url -}}
// {{- $isHtml := hasSuffix ".html" $url -}}
"hasPrefix": swapStringsFuncBoolArgsOrder(strings.HasPrefix),
"hasSuffix": swapStringsFuncBoolArgsOrder(strings.HasSuffix),

// {{- $hugeIfTrue := .SomeValue | ternary "HUGE" "not so huge" -}}
// if .SomeValue is truthy, $hugeIfTrue will be "HUGE"
// (otherwise, "not so huge")
"ternary": func(truthy interface{}, falsey interface{}, val interface{}) interface{} {
if t, ok := template.IsTrue(val); !ok {
panic(fmt.Sprintf(`template.IsTrue(%+v) says things are NOT OK`, val))
} else if t {
return truthy
} else {
return falsey
func FuncMap() template.FuncMap {
funcMap := sprig.TxtFuncMap()

// https://github.com/Masterminds/sprig/pull/276
funcMap["ternary"] = func(vt interface{}, vf interface{}, v interface{}) interface{} {
if truth, ok := template.IsTrue(v); !ok {
panic(fmt.Sprintf(`template.IsTrue(%+v) says things are NOT OK`, v))
} else if truth {
return vt
}
},
return vf
}

// First Tag: {{- .Tags | first -}}
// Last Tag: {{- .Tags | last -}}
"first": thingsActionFactory("first", true, func(args []interface{}, arg interface{}) interface{} { return arg }),
"last": thingsActionFactory("last", false, func(args []interface{}, arg interface{}) interface{} { return arg }),
// Everybody: {{- join ", " .Names -}}
// Concat: {{- join "/" "https://github.com" "jsmith" "some-repo" -}}
funcMap["join"] = stringsActionFactory("join", true, strings.Join)
// (this differs slightly from the Sprig "join" in that it accepts either a list of strings or multiple arguments - Sprig instead has an explicit "list" function which can create a list of strings *from* a list of arguments so that multiple-signature usability like this is not necessary)

// JSON data dump: {{ json . }}
// (especially nice for taking data and piping it to "jq")
// (ie "some-tool inspect --format '{{ json . }}' some-things | jq .")
"json": func(v interface{}) (string, error) {
j, err := json.Marshal(v)
return string(j), err
},

// Everybody: {{- join ", " .Names -}}
// Concat: {{- join "/" "https://github.com" "jsmith" "some-repo" -}}
"join": stringsActionFactory("join", true, strings.Join),

// {{- $mungedUrl := $url | replace "git://" "https://" | trimSuffixes ".git" -}}
// turns: git://github.com/jsmith/some-repo.git
// into: https://github.com/jsmith/some-repo
"trimPrefixes": stringsActionFactory("trimPrefixes", false, stringsModifierActionFactory(strings.TrimPrefix)),
"trimSuffixes": stringsActionFactory("trimSuffixes", false, stringsModifierActionFactory(strings.TrimSuffix)),
"replace": stringsActionFactory("replace", false, func(strs []string, str string) string {
return strings.NewReplacer(strs...).Replace(str)
}),
funcMap["json"] = funcMap["toJson"]

// {{- getenv "PATH" -}}
// {{- getenv "HOME" "no HOME set" -}}
// {{- getenv "HOME" "is set" "is NOT set (or is empty)" -}}
"getenv": thingsActionFactory("getenv", true, func(args []interface{}, arg interface{}) interface{} {
funcMap["getenv"] = thingsActionFactory("getenv", true, func(args []interface{}, arg interface{}) interface{} {
var (
val = os.Getenv(arg.(string))
setVal interface{} = val
Expand All @@ -134,5 +113,13 @@ var FuncMap = template.FuncMap{
} else {
return unsetVal
}
}),
})

// {{- $mungedUrl := $url | replace "git://" "https://" | trimSuffixes ".git" -}}
// turns: git://github.com/jsmith/some-repo.git
// into: https://github.com/jsmith/some-repo
funcMap["trimPrefixes"] = stringsActionFactory("trimPrefixes", false, stringsModifierActionFactory(strings.TrimPrefix))
funcMap["trimSuffixes"] = stringsActionFactory("trimSuffixes", false, stringsModifierActionFactory(strings.TrimSuffix))

return funcMap
}
16 changes: 8 additions & 8 deletions pkg/templatelib/lib_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

func Example_prefixSuffix() {
tmpl, err := template.New("github-or-html").Funcs(templatelib.FuncMap).Parse(`
tmpl, err := template.New("github-or-html").Funcs(templatelib.FuncMap()).Parse(`
{{- . -}}
{{- if hasPrefix "https://github.com/" . -}}
Expand Down Expand Up @@ -53,7 +53,7 @@ func Example_prefixSuffix() {
}

func Example_ternary() {
tmpl, err := template.New("huge-if-true").Funcs(templatelib.FuncMap).Parse(`
tmpl, err := template.New("huge-if-true").Funcs(templatelib.FuncMap()).Parse(`
{{- range $a := . -}}
{{ printf "%#v: %s\n" $a (ternary "HUGE" "not so huge" $a) }}
{{- end -}}
Expand Down Expand Up @@ -91,7 +91,7 @@ func Example_ternary() {
}

func Example_firstLast() {
tmpl, err := template.New("first-and-last").Funcs(templatelib.FuncMap).Parse(`First: {{ . | first }}, Last: {{ . | last }}`)
tmpl, err := template.New("first-and-last").Funcs(templatelib.FuncMap()).Parse(`First: {{ . | first }}, Last: {{ . | last }}`)

err = tmpl.Execute(os.Stdout, []interface{}{
"a",
Expand All @@ -107,7 +107,7 @@ func Example_firstLast() {
}

func Example_json() {
tmpl, err := template.New("json").Funcs(templatelib.FuncMap).Parse(`
tmpl, err := template.New("json").Funcs(templatelib.FuncMap()).Parse(`
{{- json . -}}
`)

Expand All @@ -125,7 +125,7 @@ func Example_json() {
}

func Example_join() {
tmpl, err := template.New("join").Funcs(templatelib.FuncMap).Parse(`
tmpl, err := template.New("join").Funcs(templatelib.FuncMap()).Parse(`
Array: {{ . | join ", " }}{{ "\n" -}}
Args: {{ join ", " "a" "b" "c" -}}
`)
Expand All @@ -145,7 +145,7 @@ func Example_join() {
}

func Example_trimReplaceGitToHttps() {
tmpl, err := template.New("git-to-https").Funcs(templatelib.FuncMap).Parse(`
tmpl, err := template.New("git-to-https").Funcs(templatelib.FuncMap()).Parse(`
{{- range . -}}
{{- . | replace "git://" "https://" | trimSuffixes ".git" }}{{ "\n" -}}
{{- end -}}
Expand All @@ -167,7 +167,7 @@ func Example_trimReplaceGitToHttps() {
}

func Example_trimReplaceGitToGo() {
tmpl, err := template.New("git-to-go").Funcs(templatelib.FuncMap).Parse(`
tmpl, err := template.New("git-to-go").Funcs(templatelib.FuncMap()).Parse(`
{{- range . -}}
{{- . | trimPrefixes "git://" "http://" "https://" "ssh://" | trimSuffixes ".git" }}{{ "\n" -}}
{{- end -}}
Expand All @@ -193,7 +193,7 @@ func Example_trimReplaceGitToGo() {
}

func Example_getenv() {
tmpl, err := template.New("getenv").Funcs(templatelib.FuncMap).Parse(`
tmpl, err := template.New("getenv").Funcs(templatelib.FuncMap()).Parse(`
The FOO environment variable {{ getenv "FOO" "is set" "is not set" }}. {{- "\n" -}}
BAR: {{ getenv "BAR" "not set" }} {{- "\n" -}}
BAZ: {{ getenv "BAZ" "not set" }} {{- "\n" -}}
Expand Down
4 changes: 2 additions & 2 deletions pkg/templatelib/lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
func TestTernaryPanic(t *testing.T) {
// one of the only places template.IsTrue will return "false" for the "ok" value is an UnsafePointer (hence this test)

tmpl, err := template.New("unsafe-pointer").Funcs(templatelib.FuncMap).Parse(`{{ ternary "true" "false" . }}`)
tmpl, err := template.New("unsafe-pointer").Funcs(templatelib.FuncMap()).Parse(`{{ ternary "true" "false" . }}`)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
Expand All @@ -27,7 +27,7 @@ func TestTernaryPanic(t *testing.T) {
}

func TestJoinPanic(t *testing.T) {
tmpl, err := template.New("join-no-arg").Funcs(templatelib.FuncMap).Parse(`{{ join }}`)
tmpl, err := template.New("join-no-arg").Funcs(templatelib.FuncMap()).Parse(`{{ join }}`)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
Expand Down

0 comments on commit be75a74

Please sign in to comment.