Export a function to your template.
text/template
, like some other template systems, doesn't try be good for programming in directly; it just provides a better way to stitch your data and functions with your markup, and you need to write other presentational code when it's insufficient. You can write a yourapp/template
module that exports a version of New()
that calls Funcs()
to add the common functions you use.
(You might find uses for a lot more functions than just these; Django, for example, offers lots of builtins for pluralization, formatting, i18n, etc., and folks still often extend the set.)
package main // package mytemplate
import (
"fmt"
"os"
"strings"
"text/template"
)
func conjoin(conj string, items []string) string {
if len(items) == 0 {
return ""
}
if len(items) == 1 {
return items[0]
}
if len(items) == 2 { // "a and b" not "a, and b"
return items[0] + " " + conj + " " + items[1]
}
sep := ", "
pieces := []string{items[0]}
for _, item := range items[1 : len(items)-1] {
pieces = append(pieces, sep, item)
}
pieces = append(pieces, sep, conj, " ", items[len(items)-1])
return strings.Join(pieces, "")
}
// if you use some funcs everywhere have some package export a Template constructor that makes them available, like this:
var commonFuncs = template.FuncMap{
"andlist": func(items []string) string { return conjoin("and", items) },
"orlist": func(items []string) string { return conjoin("or", items) },
}
func New(name string) *template.Template {
return template.New(name).Funcs(commonFuncs)
}
func main() {
// test conjoin
fmt.Println(conjoin("or", []string{}))
fmt.Println(conjoin("or", []string{"Bob"}))
fmt.Println(conjoin("or", []string{"Bob", "Mike"}))
fmt.Println(conjoin("or", []string{"Bob", "Mike", "Harold"}))
people := []string{"Bob", "Mike", "Harold", "Academy Award nominee William H. Macy"}
data := map[string]interface{}{"people": people}
tmpl, err := New("myyy template").Parse("{{ orlist .people }} / {{ andlist .people }}")
if err != nil {
fmt.Println("sadness:", err.Error())
return
}
err = tmpl.Execute(os.Stdout, data)
if err != nil {
fmt.Println("sadness:", err.Error())
return
}
}
Here's a variation that also exports "conjoin", and an "isLast" function you can use in a kind of verbose construction to do some arbitrary thing differently in the last go through the loop.