In one of my previous blog posts, we discovered go generate
command line
tool. Lets take the next step and evaluate its advanced benefits to generate a source code
by using our own templates. We will explore gotemplate
command line tool.
Overview
This command line tool manages package based Go
templates using go generate
.
By default it provides a set of templates that can be used out of the box:
- set - a template that generates a
set
struct for a type - list - a template that generates a
list
struct for a type - sort - a template that provides a sort primitivies for a type
- heap - a template that provides
heap
operations for a type
Installation
It is simple to install by using go get
command.
Note that the command installs the predefined templates as well.
$ go get github.com/ncw/gotemplate/...
Usage
To instaciate a particular template, you must use it using a special comment in your code:
//go:generate gotemplate "github.com/ncw/gotemplate/list" StudentList(Student)
type Student struct {
FirstName string
LastName string
BirthDate time.Time
}
Afte executing go generate
command, a file gotemplate_StudentList.go
is generated. It contains the StudentList
type that defines a list struct
that works with Student
type. It has the following methods and functions:
+StudentList : struct
[methods]
+Back() : *StudentListElement
+Front(): *StudentListElement
+Init() : *StudentList
+InsertAfter(v Student, mark *StudentListElement) : *StudentListElement
+InsertBefore(v Student, mark *StudentListElement) : *StudentListElement
+Len() : int
+MoveToBack(e *StudentListElement)
+MoveToFront(e *StudentListElement)
+PushBack(v Student) : *StudentListElement
+PushBackList(other *StudentList)
+PushFront(v Student) : *StudentListElement
+PushFrontList(other *StudentList)
+Remove(e *StudentListElement) : Student
[functions]
+NewStudentList() : *StudentList
You can use it in the following manner:
package main
import (
"fmt"
"spike/education"
)
func main() {
student := education.Student{
FirstName: "John",
LastName: "Smith",
}
list := education.NewStudentList()
list.PushFront(student)
fmt.Println(list.Front().Value.FirstName)
}
Using an initial capital when you name your template instantiation will make any external functions and types public. If you want to generate them as private you must use lower case like:
//go:generate gotemplate "github.com/ncw/gotemplate/set" stringSet(string)
//go:generate gotemplate "github.com/ncw/gotemplate/set" floatSet(float64)
Then code generation produces gotemplate_stringSet.go
and gotemplate_floateSet.go
files.
$ go generate
substituting "github.com/ncw/gotemplate/set" with stringSet(string) into package main
Written 'gotemplate_stringSet.go'
substituting "github.com/ncw/gotemplate/set" with floatSet(float64) into package main
Written 'gotemplate_floatSet.go'
Creating a custom templates
Templates must be valid go packages. They should compile and have tests and be usable as-is.
To make the package a valid template it should have one or more declarations and a special comment that declares the its template name and parameters.
The line below indicates that the base name for the template is TemplateType
and it has one type parameter TParameter
. Supported parameterized declarations
are type, const, var and func.
// template type TemplateType(TParameter)
type TParameter int
Lets implement a template for Stack data structure.
package stack
import "errors"
// template type Stack(TValue)
type TValue *int
type Stack struct {
data []TValue
}
func (s *Stack) Push(value TValue) {
s.data = append(s.data, value)
}
func (s *Stack) Pop() (TValue, error) {
length := len(s.data)
if length == 0 {
return nil, errors.New("Stack is empty")
}
value := s.data[length-1]
s.data = s.data[:length-1]
return value, nil
}
Lets declare it for Student
struct:
//go:generate gotemplate "github.com/iamralch/gotemplate/stack" StudentStack(*Student)
type Student struct {
FirstName string
LastName string
BirthDate time.Time
}
Then you can instatiate:
$ go get github.com/iamralch/gotemplate/stack
$ go generate
When the template is instantiated, a new file gotemplate_StudentStack.go
is create.
It is a result of substition of actual template with StudentStack(*Student)
declaration.
All TValue
occurances are replaced with Student
. The Stack
struct is changed to StudentStack
.
The template can be downloaded from here.
Conclusion
Gotemplate
is great tool for automatic a common development tasks. Because of its
extensibility, we can focus on what should be generated instead of how to generate it.