Mustache is a framework-agnostic, logic-free templating format that "emphasizes separating logic from presentation: it is impossible to embed application logic in this template language". It is supported in many programming languages, as shown at http://mustache.github.io. The full syntax documentation is available online at http://mustache.github.io/mustache.5.html.
Mustache is simple and versatile, its syntax is small and covers a wide range of use cases. Although it was designed to be a templating engine for HTML pages it is useful in different areas.
Norbert Hartl developed a Mustache package for Pharo. This chapter is an introduction to this package and a mini tutorial to get started with Mustache. This text is based on the original blog entries written by Norbert and extended to offer a larger covering of the Mustache features.
To install Mustache, execute the following expression in a workspace:
Gofer it
smalltalkhubUser: 'NorbertHartl' project: 'Mustache';
configuration;
loadStable
A Mustache expression takes two arguments as input: (1) a template and (2) a context object (which is a list of bindings). The latter is called a hash in Mustache jargon.
Consider a simple Mustache template (taken literally from the documentation):
templateString := 'Hello {{ name }}
You have just won ${{value}}!
{{#in_ca}}
Well, ${{taxed_value}}, after taxes.
{{/in_ca}}'.
The expression {{}}
delimits a tag or variable inside a template.
In the above example, {{ name }}
represents the variable name
. When the template is evaluated with a context, variables are replaced by their values given by a context. A possible context for the template above is the following:
context := {
'name' -> 'Chris'.
'value' -> 10000.
'taxed_value' -> (10000 - (10000 * 0.4)).
'in_ca' -> true } asDictionary
Given a context object with some bindings, we can evaluate a template in two different ways. The first one is as follows:
(MustacheTemplate on: templateString) value: context
The second way is through the asMustacheTemplate
message:
templateString asMustacheTemplate value: context
For the above example, we get the following output in both cases:
'Hello Chris
You have just won $10000!
Well, $6000.0, after taxes.
'
As context object we can use Dictionaries and Objects. Dictionaries need to have a key that is used in the template and Objects need a selector with the same name. In this chapter we use Dictionaries for brevity.
Tags can be of different types: The first and simplest type is variable.
We explain its working with an example: a {{age}}
tag in a basic template tries to find the
age
key in the current context. If there is no age
key, the parent contexts are looked up recursively. If the top context is reached and the age
key is still not found, nothing will be rendered.
The following example illustrates this. Since age
is not defined, nothing is present in the output (included below after the -->
).
'* {{name}}
* {{age}}
* {{company}}' asMustacheTemplate value:
{
'name' -> 'Chris' .
'company' -> '<b>GitHub</b>'
} asDictionary
-->
'* Chris
*
* <b>GitHub</b>'
The last line above shows that all variables are HTML escaped by default, e.g. if a binding for that variable contains a <
character it will be converted to <
. To return unescaped HTML, the
triple mustache expression must be used: {{{name}}}
. Also, the character &
can be used to unescape a variable as in {{& name}}
. This can be useful when changing delimiters, which is discussed later in this chapter.
The template below shows the different ways in which company
is escaped in the output (included below after the -->
).
'* {{name}}
* {{age}}
* {{&company}}
* {{company}}
* {{{company}}}' asMustacheTemplate value:
{
'age' -> 33 .
'name' -> 'Chris' .
'company' -> '<b>GitHub</b>'
} asDictionary
-->
'* Chris
* 33
* <b>GitHub</b>
* <b>GitHub</b>
* <b>GitHub</b>'
Sections render blocks of text a number of times if their key is present in the context. A section is delimited by a hash sign and a slash. For example, {{#number}}
begins a section for the number variable while {{/number}}
ends it.
When a variable is not present in the context the section is not present in the output:
| templateString context |
templateString := 'Shown.
{{#number}}
Shown too!
{{/number}}'.
context := { 'foo' -> 'true' } asDictionary.
(MustacheTemplate on: templateString) value: context
-->
'Shown.
'
When the variable is set, the output depends on the contents of the variable and there are three distinct cases, as we discuss next.
For values that are not collections nor blocks, the output will be present once.
For example, below number
is bound to true
which renders the text 'Shown too'
. The same will happen when number
is bound to another value, e.g. 42
.
| templateString context |
templateString := 'Shown.
{{#number}}
Shown too!
{{/number}}'.
context := { 'number' -> true } asDictionary.
(MustacheTemplate on: templateString) value: context
-->
'Shown.
Shown too!
'
There is one exception to this rule: when the variable is bound to false
the section is not present in the output:
| templateString context |
templateString := 'Shown.
{{#number}}
Shown too!
{{/number}}'.
context := { 'number' -> false } asDictionary.
(MustacheTemplate on: templateString) value: context
-->
'Shown.
'
We can use collections to create loop constructs in templates. If a section key is present in the context and it has a collection as a value, the text of the section is present as many times as there are items in the collection. Keep in mind that Strings are collections of characters.
| templateString context |
templateString := 'Shown.
{{#list}}
Shown too!
{{/list}}'.
context := { 'list' -> #(1 2 3) } asDictionary.
(MustacheTemplate on: templateString) value: context
-->
'Shown.
Shown too!
Shown too!
Shown too!
'
Consequently, if the collection is empty (or if it is the empty string), the output is present 0 times, i.e. it is absent.
When processing collections, Mustache iterates over them and for each element of the collection the context of the section is set to the current item. This allows a section to use variables that are contained in the elements of the collection. For example, below we define a list binding that contains multiple number bindings. The section list is evaluated for each of the its number bindings.
| templateString context |
templateString := 'A {{ label }} list of numbers
{{# list }}
Number: {{ number }}
{{/ list }}'.
context := {
'label' -> 'fine'.
'list' -> {
{ 'number' -> 1 } asDictionary.
{ 'number' -> 2 } asDictionary.
}
} asDictionary.
(MustacheTemplate on: templateString) value: context
-->
'A fine list of numbers
Number: 1
Number: 2
'
With such behavior we can easily generate menus and lists in html, for example:
'<ul>
{{#entries}}<li class="menuEntry{{#active}} active{{/active}}">{{label}}</li>
{{/entries}}
</ul>' asMustacheTemplate
value: { 'entries' -> {
{ 'label' -> 'first' } asDictionary.
{ 'label' -> 'second' . 'active' -> true } asDictionary.
{ 'label' -> 'third' } asDictionary } } asDictionary.
-->
'<ul>
<li class="menuEntry">first</li>
<li class="menuEntry active">second</li>
<li class="menuEntry">third</li>
</ul>'
'{{#coolBooks}}
<b>{{name}}</b>
{{/coolBooks}}' asMustacheTemplate
value: {'coolBooks' -> {
{ 'name' -> 'Pharo By Example' } asDictionary.
{ 'name' -> 'Deep Into Pharo' } asDictionary.
{ 'name' -> 'Fun Wih Pharo' } asDictionary }
} asDictionary
-->
'
<b>Pharo By Example</b>
<b>Deep Into Pharo</b>
<b>Fun Wih Pharo</b>
'
We can use Pharo blocks in context objects as well. They are evaluated at the time the template is filled out. For example,
'The alphabet: {{ alphabet }}' asMustacheTemplate
value: { 'alphabet' -> [ Character alphabet ] } asDictionary
-->
The alphabet: abcdefghijklmnopqrstuvwxyz
Now there is another interesting way of using blocks. With a block we can get access to the value of a section and perform some operations on it.
This example shows that we can access the value of a section. Here the block is expecting one argument: the value of this argument will be the section with subsituted variables.
'{{#wrapped}} {{name}} is awesome {{/wrapped}}' asMustacheTemplate
value: {
'name' -> 'Willy'.
'wrapped' -> [ :render | '<b>', render value, '</b>' ] } asDictionary.
-->
'<b> Willy is awesome </b>'.
A last use of sections is inverted sections. An inverted section begins with a caret
and ends with a slash: for example, {{^list}}
begins a an inverted section and {{/list}}
ends it. While
sections are used to render text one or more times based on the value of the key, inverted sections may render text once based on the inverse value of the key.
That is, they will be rendered if the key doesn't exist, is false, or is an empty collection:
'list{{^ list }} is {{/ list}}displayed' asMustacheTemplate
value: { 'list' -> false } asDictionary.
-->
'list is displayed'
'list{{^ list }} is {{/ list}}displayed' asMustacheTemplate
value: { 'list' -> { } } asDictionary.
-->
'list is displayed'
'list{{^ list }} is {{/ list}}displayed' asMustacheTemplate
value: { 'list' -> { 1 } } asDictionary.
-->
'listdisplayed'
Mustache templates have a notion of sub-templates that are called partials. Partial templates are useful for reusing and
composing templates out of simpler ones. Partials begin with a greater than sign, such as {{> user}}
.
The following example shows that the partial is replaced by its definition which is then expanded.
| template |
template := 'This is a test for {{> partial }} .' asMustacheTemplate.
template
value: { 'name' -> 'partial template' } asDictionary
partials: { 'partial' -> '{{name}} rendering' } asDictionary.
-->
'This is a test for partial template rendering .'
Partials work similarly with lists:
| template |
template := MustacheTemplate on:
'We can have a list ({{# list}} [ {{> partial }} ] {{/ list}}) .'.
template
value: { 'list' -> {
{ 'name' -> 'first AAA' } asDictionary.
{ 'name' -> 'last BBB' } asDictionary } } asDictionary
partials:
(Dictionary new
at: 'partial' put: (MustacheTemplate on: 'including {{name}} item');
yourself).
-->
'We can have a list ( [ including first AAA item ] [ including last BBB item ] ) .'
The values of dictionary used as template are supposed to be MustacheTemplates. However, when strings are used instead of MustacheTemplates, strings are transparently
converted, as is the case for '<strong>{{name}}</strong>'
below:
| template |
template := '<h2>Names</h2>
{{# names }}
{{> user }}
{{/ names }}' asMustacheTemplate.
template
value: {
'names' -> {
{ 'name' -> 'Username' } asDictionary } } asDictionary
partials: {'user' -> '<strong>{{name}}</strong>'} asDictionary
-->
'<h2>Names</h2>
<strong>Username</strong>
'
When you want to use Mustache to generate LaTeX you face the problem
that LaTeX may need to contain {{
and }}
, which conflicts
with the Mustache set delimiters. To avoid such conflicts the
delimiters can be changed using the =
characters separated by a space.
For example, {{=<% %>=}}
defines <%
and %>
as new delimiters. To replace the default separators, we can simply use the previously defined ones: <%={{ }}=%>
:
'{{ number }}
{{=<% %>=}}
<% number %>
<%={{ }}=%>
{{ number }}' asMustacheTemplate
value: { 'number' -> 42 } asDictionary
-->
'42
42
42'
Also, JSON is really easy to apply to the templates once NeoJSON is installed (see Chapter NeoJSON.) After that it is just as simple as in the following example:
'I can use {{name}} easily with {{format}}' asMustacheTemplate
value: (NeoJSONReader fromString:
'{ "name" : "Mustache", "format" : "JSON" }')
-->
'I can use Mustache easily with JSON'
Mustache can make template dependent tasks very easy from a simple token replacement up to nested structures to create HTML pages. We use them e.g., for generating SOAP templates. The strength of Mustache lays in the syntax and the combination of context objects. So, there is more for you to find what can be done with it. Happy templating !