A command line app for mustache.erl.
I wanted a simple command line tool to process mustache templates. Since I use rebar I already had sys.config as a mustache template and a vars file. However, after generating a release I could find no easy way to regenerate the sys.config from a different vars file without regenerating the entire release.
Using handlebar I can now generate sys.config files for new installs of erlang releases without having to regenerate the release.
To compile the code you will need rebar in your path. Then do:
make
This will produce a escript file named handlebar. Put this in your path.
handlebar finds files by optionally recursively (-r) walking directories and determines what do with the files based on extension. It needs at least one variable file and one template file in order to do anything.
The following will load one.vars as a variable file and one.src as a mustache template, the result of processing the template will be written to stdout
handlebar examples/one.vars examples/one.src
The following will load one.vars as a variable file and once.src as a mustache template, the result of processing the template will be written to the file one.file
handlebar examples/one.vars examples/one.src -o one.file
handlebar does not need files to be explicitly specified. It will find all *.vars and *.src in the current directory, process all the .src files and output the result to stdout
cd examples && handlebar
If an output directory is specified using the -d parameter, then all templates handlebar processes will be written to the directory with the .src extension removed. The following will result in out/one, out/two since there is a one.src and a two.src in the examples dir.
cd examples && handlebar -d ../out
The key to understanding the behavior of handlebar is that it recursively walks the paths provided as arguments (even if the path is a file, the file will just be loaded). Any variable file that is found is parsed with file:consult/1 and the resulting proplists are appended together. Any template file that is found is rendered through mustache:render/2 and all output is sent to stdout, a file or a directory.
A variable file is the file which lists the variables and their
values in Erlang syntax. It must be readable by file:consult/1
{one, 1}.
{two, 2}.
{a_word, "forty two"}.
The default extension for a variable file is .vars. The default extension can be changed by specifying the -E parameter.
A xtr file is a combination fo variable and template file. It is treated as a template file, however, the result of the template processing is stored in the context dictionary, NOT sent to output. This means that a xtr file named fruits.xtr will become {fruits, “content of post template processing of xtr contents”}.
A template file is a mustache template. See mustache.erl for details.
The default extension is .src. The default extension can be changed by specifying the -e parameter.
By default all output is sent to stdout. This can be changed to either a directory or a file.
To change the output to a file specify the -o parameter
To change the output to a directory specify the -d parameter
Lets assume the following directory structure:
- fruits
- trees
- apples.vars
- peaches.vars
- bush
- blueberry.vars
- fruits.xtr
- trees
- vegetables
- root.vars
- leaf.vars
- vegetables.xtr
- foods.src
We can further make some assertions about the content of the files in general, there will always be a best, worst and all. example of apples.var
{best, "Honeycrisp"}.
{worst, "Red Delicious"}.
{all, "[\"Empire\", \"Jona Gold\", \"20oz\", \"McCoun\"]"}.
{apple_favorite, "Honeycrisp"}.
fruits.xtr
There are lots of fruits out there. Of all {{all}}, the best is {{best}} and the worst is {{worst}}.
foods.src
{{fruits}} and {{vegetables}}
Lets start with the most greedy options. We want handlebar to find all data and process everything under the examples/readme dir.
cd examples/readme && ../../handlebar -r -n tree
There are lots of fruits out there. Of all ["Parsnip", "Beets", "Turnips", "Carrots"], the best is Carrot and the worst is Turnips and There are lots of vegetables out there. Of all ["Parsnip", "Beets", "Turnips", "Carrots"], the best is Carrot and the worst is Turnips
:
Not quite what we wanted to have happen! But close, so what is going on?
- handlebar looks for all *.vars files. For each vars file that is found, it is file:consult/1 and inserted into a single dictionary. This means the last vars file found has the highest precedence when resolving variable value conflicts.
- Then all *.xtr files. For each of these, it treats as a template using the current context built from the vars files. However, the xtr files are NOT sent to output, the files become variables in the context. So fruits.xtr will become {fruits, “content of file after processing”} in the context dictionary.
- Then all *.src files. For each of these mustache is run and the output is sent to specified location.
Then how do we resolve the inherent conflict in the above output? Tell handlebar that xtr are templates and process each individually.
Process the xtr as a template by changing the extenions of templates to xtr.
cd examples/readme && ../../handlebar -r -n tree -e xtr fruits | tee fruits.xtr
There are lots of fruits out there. Of all ["Redhaven", "Babygold", "Glo Haven"], the best is Glo Haven and the worst is Harbinger
Do the same for vegetables.xtr
cd examples/readme && ../../handlebar -r -n tree -e xtr vegetables | tee vegetables.xtr
There are lots of vegetables out there. Of all ["Parsnip", "Beets", "Turnips", "Carrots"], the best is Carrot and the worst is Turnips
We now have fruits.xtr and vegetables.xtr in the root directory and can munge them together into the template as we wanted to earlier.
cd examples/readme && ../../handlebar
There are lots of fruits out there. Of all ["Redhaven", "Babygold", "Glo Haven"], the best is Glo Haven and the worst is Harbinger and There are lots of vegetables out there. Of all ["Parsnip", "Beets", "Turnips", "Carrots"], the best is Carrot and the worst is Turnips
:
Outside of bugs, I consider this to be relatively feature complete. Please let me know of anything I may have overlooked.