Mustache Templates for Pharo

Stéphane Ducasse and Norbert Hartl with Johan Fabry

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.

1. Getting Started

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.

2. Tags as Variables

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
*
* &lt;b&gt;GitHub&lt;/b&gt;'

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 &lt;. 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>
* &lt;b&gt;GitHub&lt;/b&gt;
* <b>GitHub</b>'

3. Sections

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.

3.1. With the Variable Value being a 'simple' Object

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.
'

3.2. With the Variable Value being a Collection

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>
'

3.3. With the Variable Value being a Block

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>'.

3.4. Inverted Sections

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'

4. Partial templates

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>
'

5. Miscellaneous

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'

6. Templates made Easy

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 !