Provides a way of doing template execution from standard Go templates from the command line. Also includes a bundle of collection templates for strongly-typed lists, sets and maps.


License
MIT
Install
go get github.com/rickb777/runtemplate

Documentation

runtemplate

GoDoc Build Status Code Coverage Issues

This application provides a simple way of executing standard Go templates from the command line. The obvious use-case is for source code generation, amongst many others.

You can install it with:

go get github.com/rickb777/runtemplate

It is intended to be used directly from the command-line and also with go generate.

It supports light-weight dependency checking, i.e. less work is done when the generated output file already exists and is up to date.

A selection of built-in templates is included with runtemplate. These provide type-safe collection types etc.

Command-Line

Flexible option parsing is provided. Example

runtemplate -tpl filename.tpl -output outfile.go -deps foo.go,bar.go Type=MyStruct Option1:Value1 Option2:Value2
  • -tpl <name>

    • (required) the name of the input template.
  • -output <name> -o <name>

    • the name of the output file. If -tpl is not specifed, -output is required, otherwise it is optional. The name - causes writing to standard out instead of a file. Standard out is also used if this flag is unspecified and there are no key=value types.
  • -deps <name>,<name>,...

    • adds more dependencies to be checked in addition to the template itself and the 'type' file (if any).
  • -f

    • force output generation; if this is not set the output file is only produced when it is older than the dependencies
  • -v

    • verbose info messages
  • key:value ...

    • (optional) supply a (list of) simple key/value pairs that are passed in to the template. true and false are converted to booleans, allowing conditional blocks within your templates.
  • key=value ...

    • (optional) supply a (list of) key/value pairs that are passed in to the template. These are often Go types; extra synthetic values are also added, making it really easy to generate source code. This is described further below. true and false are converted to booleans, allowing conditional blocks within your templates.

The option parser will also infer the template and output file names, so it is also permitted to use either

runtemplate -output outfile.go -tpl filename.tpl Type=MyStruct Option1:Value1 Option2:true
runtemplate outfile.go filename.tpl Type=MyStruct Option1:Value1 Option2:true

i.e. to omit the explicit flags -tpl and -output provided the files are named.

Furthermore, the output file may be completely omitted:

runtemplate filename.tpl Type=MyStruct Option1=Value1 Option2=true Option3:foo

in which case a name will be computed from all the values of the key=value pairs (excluding true/false) in the order they are specified, plus the name of the template, conjoined with underscores, plus the extension '.go'. All the key:value settings are excluded.

For the example above, it will be mystruct_value1_filename.go because Option2 and Option3 are ignored for the reasons above.

Go Generate

Easy. Just put the go generate comment in your code like this:

//go:generate runtemplate -tpl filename.tpl -output outfile.go Option1=Value1 Option2:Value2

When you run go generate, it will find these marked comments and execute their commands. This will runtemplate against the specified template, passing in whatever options have have been specified on the command line as a map.

Template

In the template file, you can access the key=value or key:value pairs simply by their keys. For instance:

{{ .Option1 }}

Boolean true/false key-values are available for {{if .Flag}} ... {{end}} conditional use. Undefined values default to false.

Simple Keys

The key:value syntax (using colon) defines simple values. These can be repeated to supply a slice of values, which is useful for the template range operator.

The values true and false are converted to booleans.

Foo:Bar Foo:Ban Foo:Bar Foo:Baz
.Foo Bar {Ban, Bar, Baz}
.HasFoo true true

Keys for Types

The key=value syntax (using equals) does more and is intended for identifiers in the programming language of the generated code (usually Go).

Type Details

Unlike most of runtemplate behaviour, the type definition can become quite specific to Go (in other contexts, what follows may not be wholly relevant).

It is possible to give aliases for types. Specifically, the string following Type= contains one, two or three slash-separated parts. The simple case is like Type=string, i.e. one part; this becomes the alias String when composing identifiers. When required, the zero value for the type is computed: specifically, for built-in types the zero value is well defined; for other types, the zero value is obtained using the new built-in.

For types such as interface{}, this doesn't work because it cannot form any part of an identifier due to the braces. So there is a common use-case; for example it is valid to use Type=interface{}/Any/nil; here, the three parts represent the type itself (interface{}), the alias (Any), and the expression used for the zero value (nil).

If only two parts are present, e.g. Type=foo/Bar, the type and alias are defined but the absent zero value follows the default rule described above.

Using Types in Templates

The values are supplemented by additional entries in the template's context. For example, given Type=SomeValue or Type=*SomeValue, these are:

  • .Type - the type name (prefixed by '*' if supplied)
  • .Type.String - same as above (because this is simply a string, it may be used in '==' comparisons)
  • .Type.Name - the type name (without any '*' prefix)
  • .Type.U - the type alias having its first character converted to uppercase - useful for exported identifiers; dots are removed.
  • .Type.L - the type alias having its first character converted to lowercase - useful for internal identifiers; dots are removed.
  • .Type.IsPtr - boolean indicating whether '*' is supplide
  • .Type.Star - a '*' if the type is a pointer type, otherwise blank
  • .Type.Amp - a '&' if the type is a pointer type, otherwise blank
  • .Type.Zero - nil if the type is a pointer type, otherwise the zero value for the type
  • .Type.Ident - the type alias as a RichString that has several extra methods (ToUpper, ToLower etc)
  • .HasType - set to true to allow conditional expressions (it defaults to false if undefined)

This table shows two examples of context symbols defined for Type=big.Int and Type=*big.Int.

Type=big.Int Type=*big.Int
.Type big.Int *big.Int
.Type.Name big.Int big.Int
.Type.U BigInt BigInt
.Type.L bigInt bigInt
.Type.IsPtr false true
.Type.Star blank *
.Type.Amp blank &
.Type.Zero *(new(big.Int)) nil
.HasType true true

Be aware that your shell might expand * so you may need suitable quote marks, such as 'Type=*Foo'. This is not needed when using go:generate comment lines.

Prefix

If you need to generate code for several generated types and they need to co-exist within the same package, you can easily define a prefix to differentiate their names.

For every <X>Type template value that you specify (for some <X>), there is a corresponding special value <X>Prefix that is always predefined with a blank default value. But you can set it to something else, and if you do the generated types can use this to prefix their names. This only happens for keys that end in Type.

In short, the key's suffix Type is replaced with Prefix.

As well as <X>Prefix, there will be <X>UPrefix and <X>LPrefix as above.

Other settings

Additional settings are also made available:

  • .OutFile - the name of the output file
  • .TemplateFile - the template name as specified
  • .TemplatePath - the location and name of the actual template file used
  • .Package - the name of the directory of the output file (often the current directory)
  • .AppVersion - the version of Runtemplate that is being used
  • .GOARCH, .GOOS, .GOPATH, GOROOT - the value of Go environment variables.

Some filters are also included that may be helpful.

  • title - Converts the input to Title Case.
  • upper - Converts the input to UPPER CASE.
  • lower - Converts the input to lower case.
  • firstUpper - Converts the first character of input to upper case.
  • firstLower - Converts the first character of input to lower case.
  • condFirstUpper - Given a string and a boolean, converts the first character of input to upper case when the boolean is true.
  • splitDotFirst - Given an input that has a '.' separator, returns the part before the first '.'.
  • splitDotLast - Given an input that has a '.' separator, returns the part after the last '.'.

The last two are useful for getting only the package name or only the type name if passed an input of package.Type.

Template Path

Templates are located by following TEMPLATEPATH, an optional environment variable. If it is defined, it is used like PATH, i.e. a colon-separate list of directories to be searched.

If TEMPLATEPATH is absent, its default is TEMPLATEPATH=., i.e. templates are relative to the current directory.

The builtin templates are also available and are searched if no other match is found. For example, template "types/stringy.tpl" will resolve to the built-in template of that name unless the TEMPLATEPATH contains another file with the same path.

Built-in Templates

A selection of built-in templates is included with runtemplate. These provide type-safe collection types. Their API style has been loosely influenced by other similar Go types and the excellent Scala collection classes.

See BUILTIN