pgot (process golang template) is a lightweight command line template processing utility. It directly leverages the golang template package from the standard library. pgot processes files that contain a combination of frontmatter followed by a template. The frontmatter consists of JSON formatted data, and the template that follows is free form text containing actions. By convention, files to be processed by pgot are referred to as "got" (golang template) files and have a ".got" filename extension although this is not a requirement.
The pgot utility implements a "pgotInclude" keyword that can be defined in frontmatter to include (aka import) other got files. Each of these included files can also include other got files if desired. The number of nested includes is limited only by memory and the number of open files allowed by the operating system.
Both the frontmatter and the template from an included got file can be leveraged by the originating got file. The imported template is accessed via a template action using the name of the file minus its extension. By default, imported frontmatter is merged into the global namespace (aka "."), however pgotInclude also has the option of importing into a separate namespace if desired to avoid data naming collisions. Although pgot is small in size these features along with the comprehensive actions available in the standard template library enable a large range of applications from simple to large scale complex text file hierarchies.
The range of uses is quite large, but a few examples include:
-
A simple README, LICENSE, or CONTRIBUTING template with standard sections that an author can leverage across various git repositories (the pgot source code repository is an example).
-
A static website using imported pgot templates to standardize website appearance, headers, footers, etc. (https://blog.lenzplace.org is an example).
-
A mail merge script to generate tailored messages for each recipient.
-
A large book written in markdown or latex with metadata in frontmatter for authors, chapters, references, contributors, keywords, etc.
Usage: pgot [OPTION]... [FILE]...
Read a got (golang template) file and send transformed text to output.
Options:
-d string
string of json frontmatter to include
-i paths
colon separated list of paths to search with pgotInclude
-o file
output file path (default "-")
If no files are specified on the command line, then pgot reads from sdtin. Similarly if the -o option is not used, the output is sent to stdout (aka "-"). If multiple files are specified on the command line the last file listed is the primary or root file with previous files being included in a way similar to how the "pgotInclude" keyword works in frontmatter.
The -d option can be used to insert frontmatter from the command line. This frontmatter is merged into the global (aka ".") namespace and takes precedence or overwrites any frontmatter read in from the main got file or included files.
The path(s) specified with the -i option can include absolute or relative paths. An empty path in the -i option (the default) indicates that the local path relative to the respective got file should be searched. A few examples below shed further light on this:
pgot -i "" myfile.got
This is the same as the default for the -i option. For any relative files
specified using pgotInclude, the base dir of the calling got file will be
where the relative path starts.
pgot -i ":/home/veronica/pgot-inc" myfile.got
The folder of the calling got file will be searched first (nothing before
the first ":") and if the file is not found there it will then search the
"/home/veronica/pgot-inc" folder.
pgot -i "/home/larry/inc1::/home/larry/inc2" myfile.got
The inc1 folder will be searched first, followed by the folder the calling
got file is in, followed by the inc2 folder.
A got file must include a frontmatter JSON section bounded by three semicolons each on their own line before and after the JSON data. Anything after this frontmatter section is considered to be the "template" which is processed by the golang template package. The full documentation of the template actions provided by the golang library is available here. Note that it is acceptable to have an empty frontmatter section or template section or both.
The following examples also exist in the "tests" sub folder within this repository. A minimal (although admittedly useless) got file consists of the following:
;;;
;;;
A slightly more relevant got file:
;;;
{ "name" : "Jason" }
;;;
Hello world, my name is {{.name}}
And a more advanced example leveraged from here:
;;;
{
"guests" : [
["Aunt Mildred", "bone china tea set", true],
["Uncle John", "moleskin pants", false],
["Cousin Rodney", "", false]
]
}
;;;
{{range .guests -}}
Dear {{index . 0}},
{{if index . 2}}
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 index . 1 -}}
Thank you for the lovely {{.}}.
{{end}}
Best wishes,
Josie
---
{{end -}}
Any valid JSON structure can be used in the frontmatter section. There is however one keyword that is reserved when used in frontmatter.
pgotInclude
"pgotInclude" : [ "file1.got", "file2.got", "file3.got" ]
"pgotInclude" : [ { "f":"file1.got", "n":"name1" },
{ "f":"file2.got", "n":"name2" },
{ "f":"file3.got", "n":"name3" } ]
The pgotInclude keyword is used to include (aka import) other pgot files and can be used in one of two variations as shown above. Note that three files are showdn in the above variations, however any number of files can be included (from one to the limits of memory and the filesystem).
The first variation above imports each got file in the order defined in the array. The frontmatter is merged directly into the top level "." namespace. If two imported got files contain the same data element name, the last file included takes precedence. In other words, file3 would take precedence over file2, and file1. Lastly, any frontmatter defined in the originating got file (the file called directly by pgot) is included last and takes precedence (overwrites) any included data structures that have the same element name.
The second variation can be used to import frontmatter into the specified namespace which can be useful to avoid data collisions or overwriting. For example if file1 defines an element "color" : "Purple", and file2 defines "color" : "Green", they can both be accessed separately via {{.name1.color}}, and {{.name2.color}}.
It's important to note that the included got filenames may be specified with relative or absolute paths. For relative paths the the included got file is relative to the location of the originating got file.
Note that future keywords may be created which start with "pgot", so it is advisable to avoid naming any elements in frontmatter starting with "pgot".
In addition to the standard template actions, there are currently two custom template actions defined by pgot (below). These are included more as simple examples rather than critical features. For those interested in implementing custom template actions the gotFuncs.go source code demonstrates how custom template actions can be added.
{{lnp "label" "url"}}
lnp (link new page) generates the specified url as an html link which opens a new page when the user selects the link. If label is nil (aka "") then the url is displayed as the clickable link, otherwise the label itself is displayed.
{{toInt value}}
toInt (to integer) is able to convert a value parameter to an integer. Multiple types can be handled. For example a string representation of a number can be converted. This can also convert the JSON default number type (float64) to an integer.
- Go compiler (v1.12 or later).
- Go package chunkio
- Go package testcli to run tests.
- Scdoc utility to generate the man page. Only needed if changes to man page sources are made.
- pgot (this utility) to process files in the templates sub folder. Only needed if changes to README.md, LICENCE, Makefile etc. are needed.
$ make
# make install
$ make check
If you have a bugfix, update, issue or feature enhancement the best way to reach me is by following the instructions in the link below. Thank you!
https://blog.lenzplace.org/contact
I follow the SemVer strategy for versioning. The latest version is listed in the releases section.
This project is licensed under a BSD two clause license - see the LICENSE file for details.
Q: What causes the following error message: "pgot : invalid character '}' looking for beginning of object key string"?
A: This is an error message from the golang JSON library. The frontmatter is likely not valid structured JSON. Make sure you don't have something like the following. The last comma in the "copyright" row should be deleted.
;;;
{
"author" : "Jose",
"date" : "March 6th, 2019",
"copyright" : "2019",
}
;;;
Q: I keep getting '<no value>' in parts of my output?
A: This is what the golang template engine outputs when a pipeline is undefined. It can sometimes be handy when debugging golang templates to include {{.}} somewhere in the template. This displays all the elements in the global pipeline defined at time of template execution.