You'll learn here how GRMustache renders your data. The loading of templates is covered in the Templates Guide. Common patterns for feeding templates are described in the ViewModel Guide.
Variable tags {{ name }}
and {{{ name }}}
look for the name
key in the object you provide:
id data = @{ @"name": @"Arthur" };
// Renders "Hello Arthur!"
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:@"Hello {{name}}!"
error:NULL];
Any Key-Value Coding compliant object that responds to the valueForKey:
method can be used.
Dictionaries are such objects. So are, generally speaking, your custom models:
// The Person class defines the `name` property:
Person *barbara = [Person personWithName:@"Barbara"];
// Renders "Hello Barbara!"
NSString *rendering = [GRMustacheTemplate renderObject:barbara
fromString:@"Hello {{name}}!"
error:NULL];
Remember that {{ name }}
renders HTML-escaped values, when {{{ name }}}
and {{& name }}
render unescaped values.
Objects are usually rendered with the standard description
method, with two exceptions:
- Your custom objects that take full charge of their own rendering. See the Rendering Objects Guide for further details.
- Objects conforming to the NSFastEnumeration protocol (but NSDictionary):
A variable tag renders all items of enumerable objects:
id data = @{ @"voyels": @[@"A", @"E", @"I", @"O", @"U"] };
// Renders "AEIOU"
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:@"{{voyels}}"
error:NULL];
This especially comes handy with your custom rendering objects: you may think of Ruby on Rails' <%= render @items %>
.
Variable tags render simple keys as seen above, and, more generally, expressions, such as the key path person.name
and the filtered expression uppercase(person.name)
.
Person *craig = [Person personWithName:@"Craig"];
id data = @{ @"person": craig };
// Renders "Hello CRAIG!"
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:@"Hello {{ uppercase(person.name) }}!"
error:NULL];
GRMustache first looks for the person
key, extracts its name
, and applies the uppercase
built-in filter of the standard library. The variable tag eventually renders the resulting string.
The rendering of section tags such as {{# name }}...{{/ name }}
and {{^ name }}...{{/ name }}
depend on the value attached to the name
expression.
Generally speaking, inverted sections {{^ name }}...{{/ name }}
render when regular sections {{# name }}...{{/ name }}
do not. You can think of the caret ^
as the Mustache "unless".
Precisely speaking:
If the value is false, regular sections are omitted, and inverted sections rendered:
id data = @{ @"red": @NO, @"blue": @YES };
// Renders "Not red"
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:@"{{#red}}Red{{/red}}{{^red}}Not red{{/red}}"
error:NULL];
// Renders "Blue"
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:@"{{#blue}}Blue{{/blue}}{{^blue}}Not blue{{/blue}}"
error:NULL];
When an inverted sections follows a regular section with the same expression, you can use the short {{# name }}...{{^ name }}...{{/ name }}
form, avoiding the closing tag for {{# name }}
. Think of "if ... else ... end". For brevity's sake, you can also omit the expression after the opening tag: {{#name}}...{{^}}...{{/}}
is valid.
The full list of false values are:
nil
and missing keys[NSNull null]
NSNumber
instances whoseboolValue
method returnsNO
- empty strings
@""
- empty enumerables.
They all prevent Mustache sections {{# name }}...{{/ name }}
rendering.
They all trigger inverted sections {{^ name }}...{{/ name }}
rendering.
If the value attached to a section conforms to the NSFastEnumeration protocol (except NSDictionary), regular sections are rendered as many times as there are items in the enumerable object:
NSArray *friends = @[
[Person personWithName:@"Dennis"],
[Person personWithName:@"Eugene"],
[Person personWithName:@"Fiona"]];
id data = @{ @"friends": friends };
NSString *templateString = @"My friends are:\n"
@"{{# friends }}"
@"- {{ name }}\n"
@"{{/ friends }}";
// My friends are:
// - Dennis
// - Eugene
// - Fiona
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:templateString
error:NULL];
Each item in the collection gets, each on its turn, available for the key lookup: that is how the {{ name }}
tag renders each of my friend's name.
Inverted sections render if and only if the collection is empty:
id data = @{ @"friends": @[] }; // empty array
NSString *templateString = @"{{^ friends }}"
@"I have no friend, sob."
@"{{/ friends }}";
// I have no friend, sob.
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:templateString
error:NULL];
You may render a collection of strings with the dot expression .
, aka "implicit iterator":
id data = @{ @"items": @[@"Ham", @"Jam"] };
NSString *templateString = @"{{# items }}"
@"- {{ . }}"
@"{{/ items }}";
// - Ham
// - Jam
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:templateString
error:NULL];
Sections render as many times as they contain items.
However, you may want to render a section once if and only if a collection is not empty. For example, when rendering a single <ul>
HTML element that wraps several <li>
.
A template that is compatible with other Mustache implementations needs an extra boolean key that states whether the collection is empty or not:
NSArray *friends = ...;
id data = @{
@"hasFriends": @(friends.count > 0),
@"friends": friends };
NSString *templateString = @"{{# hasFriends }}"
@"<ul>"
@" {{# friends }}"
@" <li>{{ name }}</li>"
@" {{/ friends }}";
@"</ul>"
@"{{/ hasFriends }}";
// <ul>
// <li>Dennis</li>
// <li>Eugene</li>
// <li>Fiona</li>
// </ul>
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:templateString
error:NULL];
If you do not care about compatibility, you can simply use the count
property of NSArray, and use the fact that GRMustache considers zero numbers as false:
NSArray *friends = ...;
id data = @{ @"friends": friends };
NSString *templateString = @"{{# friends.count }}"
@"<ul>"
@" {{# friends }}"
@" <li>{{ name }}</li>"
@" {{/ friends }}";
@"</ul>"
@"{{/ friends.count }}";
// <ul>
// <li>Dennis</li>
// <li>Eugene</li>
// <li>Fiona</li>
// </ul>
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:templateString
error:NULL];
Mustache defines lambda sections, that is, sections that execute your own application code, and allow you to extend the core Mustache engine.
Such sections are fully documented in the Rendering Objects Guide, but here is a preview:
id data = @{
@"name1": @"Gustave",
@"name2": @"Henriett" };
NSString *templateString = @"{{#localize}}Hello {{name1}}, do you know {{name2}}?{{/localize}}";
// Assuming a Spanish locale:
// Hola Gustave, sabes Henriett?
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:templateString
error:NULL];
The localize
key is attached to a rendering object that is built in the standard library shipped with GRMustache.
When a section renders a value that is not false, not enumerable, not a rendering object, it renders once, making the value available for the key lookup inside the section:
Person *ignacio = [Person personWithName:@"Ignacio"];
id data = @{ @"person": ignacio };
// Renders "Hello Ignacio!"
NSString *templateString = @"{{# person }}Hello {{ name }}!{{/ person }}";
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:templateString
error:NULL];
Just as variable tags, section tags render any well-formed expressions:
id data = @{
@"person": @{
@"friends": @[
[Person personWithName:@"José"],
[Person personWithName:@"Karl"],
[Person personWithName:@"Lubitza"]]
}
};
NSString *templateString = @"{{# withPosition(person.friends) }}"
@" {{ position }}: {{ name }}"
@"{{/}}";
// 1: José
// 2: Karl
// 3: Lubitza
NSString *rendering = [GRMustacheTemplate renderObject:data
fromString:templateString
error:NULL];
The withPosition
filter returns a rendering object that makes the position
key available inside the section. It is described in the Collection Indexes Sample Code.
We have seen that values rendered by sections are made available for the key lookup inside the section.
As a matter of fact, objects that were the context of enclosing sections are still available: the latest object has just entered the top of the context stack.
An example should make this clearer. Let's consider the template below:
{{# title }}
{{ length }}
{{/ title }}
{{# title }}
{{ title }}
{{/ title }}
In the first section, the length
key will be fetched from the title
string which has just entered the context stack: it will be rendered as "6" if the title is "Hamlet".
In the last section, the title string is still the context. However it has no title
key. Thus GRMustache looks for it in the enclosing context, finds again the title string, and renders it:
6
Hamlet
This technique allows, for example, the conditional rendering of a <h1>
HTML tag if and only if the title is not empty (empty strings are considered false, see "false sections" above):
{{# title }}
<h1>{{ title }}</h1> {{! rendered if there is a title }}
{{/ title }}
These three template snippets are quite similar, but not stricly equivalent:
...{{# foo }}{{ bar }}{{/ foo }}...
...{{# foo }}{{ .bar }}{{/ foo }}...
...{{ foo.bar }}...
The first will look for bar
anywhere in the context stack, starting with the foo
object.
The two others are identical: they ensure the bar
key comes from the very foo
object. If foo
is not found, the bar
lookup will fail as well, regardless of bar
keys defined by enclosing contexts.
Protected contexts let you make sure some keys get always evaluated to the same value, regardless of objects that enter the context stack. Check the Protected Contexts Guide.
Values extracted from the context stack are directly rendered unless you had some tag delegates enter the game. They help you render default values for missing keys, for example. See the Tag Delegates Guide for a full discussion.
As seen above, GRMustache looks for a key in your data objects with the valueForKey:
method. With some extra bits.
NSDictionary never complains when asked for an unknown key. However, the default NSObject implementation of valueForKey:
raises an NSUndefinedKeyException
.
GRMustache catches those exceptions, so that the key lookup can continue down the context stack.
When debugging your project, NSUndefinedKeyException raised by template rendering may become a real annoyance, because it's likely you've told your debugger to stop on every Objective-C exceptions.
You can avoid that: make sure you invoke once, early in your application, the following method:
[GRMustache preventNSUndefinedKeyExceptionAttack];
Depending on the number of NSUndefinedKeyException that get prevented, you will experience a slight performance hit, or a performance improvement.
Since the main use case for this method is to avoid Xcode breaks on rendering exceptions, the best practice is to conditionally invoke this method, using the NS_BLOCK_ASSERTIONS that helps identifying the Debug configuration of your targets:
#if !defined(NS_BLOCK_ASSERTIONS)
// Debug configuration: keep GRMustache quiet
[GRMustache preventNSUndefinedKeyExceptionAttack];
#endif
GRMustache shunts the valueForKey: implementation of Foundation collections to NSObject's one.
It is little know that the implementation of valueForKey:
of Foundation collections return another collection containing the results of invoking valueForKey:
using the key on each of the collection's objects.
This is very handy, but this clashes with the rule of least surprise in the context of Mustache template rendering.
First, {{collection.count}}
would not render the number of objects in the collection. {{#collection.count}}...{{/}}
would not conditionally render if and only if the array is not empty. This has bitten at least one GRMustache user, and this should not happen again.
Second, {{#collection.name}}{{.}}{{/}}
would render the same as {{#collection}}{{name}}{{/}}
. No sane user would ever try to use the convoluted first syntax. But sane users want a clean and clear failure when their code has a bug, leading to GRMustache not render the object they expect. When object
resolves to an unexpected collection, object.name
should behave like a missing key, not like a key that returns an unexpected collection with weird and hard-to-debug side effects.
Based on this rationale, GRMustache uses the implementation of valueForKey:
of NSObject
for arrays, sets, and ordered sets. As a consequence, the count
key can be used in templates, and no unexpected collections comes messing with the rendering.
The Mustache specification does not enforce the list of false values, the values that trigger or prevent the rendering of sections and inverted sections:
There is no guarantee that {{# value }}...{{/ value }}
and {{^ value }}...{{/ value }}
will render the same, provided with the exact same input, in all Mustache implementations.
That's unfortunate. Anyway, for the record, here is a reminder of all false values in GRMustache:
nil
and missing keys[NSNull null]
NSNumber
instances whoseboolValue
method returnsNO
- empty strings
@""
- empty enumerables.