Command gemplate

Command gemplate compiles data-driven templates for generating textual output into Go. This template language closely matches the standard library, except that it is meant to be compiled ahead of time and that the templates are statically typed.
With one exception, the template language understood by gemplate exactly matches syntatically the text/template package in the standard library. That one exception is that {{define ...}} blocks require two parameters instead of one. The additional parameter specifies a static type for the template. More details are covered in the section below.
Install
The package can be installed from the command line using the go tool. It requires Go 1.18 or later (see go.mod).
go install git.sr.ht/~rj/gemplate@latest
Basic usage information can be obtained by asking for help from the command line.
gemplate --help
Getting Started
To start, you will need a template. One can begin with the an example from the standard library. Copy the following into a file called letter.tmpl.
Dear {{.Name}},
{{if .Attended}}
It was a pleasure to see you at the wedding.
{{- else}}
It is a shame you couldn't make it to the wedding.
{{- end}}
{{with .Gift -}}
Thank you for the lovely {{.}}.
{{end}}
Best wishes,
Josie
Unlike when executing the template at runtime, the compiler needs to know the static types for the templates. For example, to check that the field .Attended is a boolean, and .Gift is a string. This is accomplished by parsing the existing Go source. In the same directory, create a driver for the template, which will also describe the necessary types.
package main
import (
"log"
"os"
)
// Prepare some data to insert into the template.
type Recipient struct {
Name, Gift string
Attended bool
}
// Contents to be printed. Details are ellided for brevity.
// See testdata/example1.
var recipients = []Recipient{}
func main() {
for _, r := range recipients {
err := letter(os.Stdout, &r)
if err != nil {
log.Println("executing template:", err)
}
}
}
Note that the function main calls out to letter, but that function has not yet been defined. Before the package can be run or built, the template needs to be compiled:
gemplate --output=letter.go --dot="*Recipient" letter.tmpl
And then the driver can be run:
go run main.go letter.go
Differences from the Standard Library
All of the documentation from the standard library basically holds. The key exception is that the syntax of nested template definitions takes an additional parameter. The second parameter defines the static type for the cursor (often called dot). For example, the following two template definitions:
{{define "T1" "string"}}ONE{{end}}
{{define "T2" "*T"}}TWO{{end}}
The above will, after being compiled to Go source code, create the following two functions:
func T1(io.Writer, string) error
func T2(io.Writer, *T) error
External Functions
When compiling a template, any functions in the package are also made available to the template, and can be used inside of pipelines. The behaviour roughly follows the behaviour of text/template, except that the list of available functions is found by analyzing the package. Any function which returns a single value can be used in this manner.
For example, the following function will be available to be called by templates.
// toupper is a function that will be available in templates.
func toupper(s string) string {
return strings.ToUpper(s)
}
The function can then be used inside of templates.
{{define "hello" "string"}}Hello, {{toupper .}}{{end}}
External Templates
Functions in the package with the correct signature can be invoked with a {{template}} action. The functions must have the correct signature, which matches the signature of templates as generated by gemplate.
func mytemplate(io.Writer, DotType) error
For example, the following function would be usable as a template:
func formatBool(w io.Writer, dot bool) error {
_, err := io.WriteString(w, strconv.FormatBool(dot))
return err
}
The external template can be used by other templates, such as:
{{define "T1" "bool"}}Hello, {{template "formatBool" .}}{{end}}
Contribute
To submit bug reports and suggestions, please use the issue tracker.
Discussions occur using the mailing list. The mailing list can also be used to submit patches.
Scope
This package aims to provide a template syntax that matches the package text/template from the standard library, with limited changes to support static typing of the template.
- text/template: Package template implements data-driven templates for generating textual output.
- templ: Build HTML with Go.
License
BSD (c) Robert Johnstone