Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 836 lines (544 sloc) 35.789 kb
f01775d @groue README
authored
1 GRMustache
2 ==========
3
18dc85c @groue v1.8.0
authored
4 GRMustache is an Objective-C implementation of the [Mustache](http://mustache.github.com/) logic-less template engine, for MacOS 10.6+, iPhoneOS 3.0, iOS 4.0, and iOS 5.0.
f01775d @groue README
authored
5
18dc85c @groue v1.8.0
authored
6 It supports the [regular Mustache syntax](http://mustache.github.com/mustache.5.html), the [Mustache specification v1.1.2](https://github.com/mustache/spec), except for whitespace management (more on that below), and language extensions brought by [Handlebars.js](https://github.com/wycats/handlebars.js).
f01775d @groue README
authored
7
18dc85c @groue v1.8.0
authored
8 Full features list:
f01775d @groue README
authored
9
18dc85c @groue v1.8.0
authored
10 - HTML-escaped variable tags: `{{name}}`
11 - Unescaped variable tags: `{{{name}}}` and `{{&name}}`
12 - Sections (boolean, enumerable, inverted, lambdas): `{{#name}}...{{/name}}`
13 - partials (and recursive partials): `{{>name}}`
14 - delimiter changes: `{{=<% %>=}}`
15 - comments: `{{!...}}`
16 - "dotted names": `{{foo.bar}}`
17 - "implicit iterator": `{{.}}`
18 - "extended paths" of [Handlebars.js](https://github.com/wycats/handlebars.js): `{{../foo/bar}}`
070c126 @groue dot variable extension
authored
19
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
20 On top of the core Mustache engine, GRMustache ships with a few handy stuff:
21
22 - Number formatting
23 - Date formatting
24
18dc85c @groue v1.8.0
authored
25 Note that:
26
27 - GRMustache does not honor the whitespace management rules of the [Mustache specification v1.1.2](https://github.com/mustache/spec): each character of your templates will be rendered as is.
28 - The default rendering of GRMustache is compatible with [Handlebars.js](https://github.com/wycats/handlebars.js). This means that support for "extended paths" such as `{{../foo/bar}}` is enabled by default. In order to use the "dotted names" of [Mustache v1.1.2](https://github.com/mustache/spec), such as `{{foo.bar}}`, you will have to ask for them explicitely.
070c126 @groue dot variable extension
authored
29
ffb6fa1 @groue Some rewording
authored
30 ### Embedding in your XCode project
945eb6d @groue more README
authored
31
18dc85c @groue v1.8.0
authored
32 GRMustache ships as a static library and a header file, and only depends on the Foundation.framework.
33
34 The `GRMustache.h` header file is located into the `/include` folder at the root of the GRMustache repository. Add it to your project.
35
36 You'll have next to choose a static library among those located in the `/lib` folder:
37
38 - `libGRMustache1-ios3.a`
39 - `libGRMustache1-ios4.a`
40 - `libGRMustache1-macosx10.6.a`
41
42 `libGRMustache1-ios3.a` targets iOS3+, and include both device and simulator architectures (i386 armv6 armv7). This means that this single static library allows you to run GRMustache on both simulator and iOS devices.
43
44 `libGRMustache1-ios4.a` targets iOS4+, and include both device and simulator architectures (i386 armv6 armv7). On top of all the APIs provided by `libGRMustache1-ios3.a`, you'll find blocks and NSURL* APIs in this version of the lib.
945eb6d @groue more README
authored
45
18dc85c @groue v1.8.0
authored
46 `libGRMustache1-macosx10.6.a` targets MaxOSX 10.6+. It includes both 32 and 64 bits architectures (i386 x86_64), and the full set of GRMustache APIs.
945eb6d @groue more README
authored
47
9814fbf @groue APR clarification
authored
48 ### Versioning and backward compatibility
0219c22 @groue v1.0.0
authored
49
9814fbf @groue APR clarification
authored
50 Until GRMustache hits version 2, there is no risk upgrading GRMustache in your project: you will get bugfixes and improvements without changing a line of your code.
97104d4 @groue Exchange "Versioning" and "Testing" section in README.md
authored
51
9814fbf @groue APR clarification
authored
52 You may well get deprecation warnings, but these are only warnings. Support for deprecated APIs will only be removed in the next major version.
53
54 This is because GRMustache versioning policy complies to the one defined by the [Apache APR](http://apr.apache.org/versioning.html).
55
56 Check the [release notes](https://github.com/groue/GRMustache/blob/master/RELEASE_NOTES.md) for more information, and [Follow us on twitter](http://twitter.com/GRMustache) for breaking development news.
730c37a @groue twitter link
authored
57
4ef5eef @groue Note on forking
authored
58 ### Forking
59
60 Please fork, and read the [Note on forking](https://github.com/groue/GRMustache/wiki/Note-on-forking) wiki page.
61
3a0ab34 @groue wording
authored
62 ### Advanced topics
63
64 This README file provides with basic GRMustache documentation. Check out the [wiki](https://github.com/groue/GRMustache/wiki) for discussions on some more advanced topics.
65
f01775d @groue README
authored
66 Simple example
67 --------------
68
69 #import "GRMustache.h"
70
71 NSDictionary *object = [NSDictionary dictionaryWithObject:@"Mom" forKey:@"name"];
72 [GRMustacheTemplate renderObject:object fromString:@"Hi {{name}}!" error:nil];
73 // returns @"Hi Mom!"
74
75 Rendering methods
76 -----------------
77
3c453f8 @groue typo
authored
78 The main rendering methods provided by the GRMustacheTemplate class are:
f01775d @groue README
authored
79
80 // Renders the provided templateString.
81 + (NSString *)renderObject:(id)object
82 fromString:(NSString *)templateString
83 error:(NSError **)outError;
84
a1f2cf1 @groue v1.4.0
authored
85 // Renders the template loaded from a url. (from MacOS 10.6 and iOS 4.0)
f01775d @groue README
authored
86 + (NSString *)renderObject:(id)object
87 fromContentsOfURL:(NSURL *)url
88 error:(NSError **)outError;
89
a1f2cf1 @groue v1.4.0
authored
90 // Renders the template loaded from a path.
91 + (NSString *)renderObject:(id)object
92 fromContentsOfFile:(NSString *)path
93 error:(NSError **)outError;
94
f01775d @groue README
authored
95 // Renders the template loaded from a bundle resource of extension "mustache".
96 + (NSString *)renderObject:(id)object
97 fromResource:(NSString *)name
98 bundle:(NSBundle *)bundle
99 error:(NSError **)outError;
100
101 // Renders the template loaded from a bundle resource of provided extension.
102 + (NSString *)renderObject:(id)object
103 fromResource:(NSString *)name
104 withExtension:(NSString *)ext
105 bundle:(NSBundle *)bundle
106 error:(NSError **)outError;
107
18dc85c @groue v1.8.0
authored
108 All those methods perform a rendering that is compatible with [Handlebars.js](https://github.com/wycats/handlebars.js) and its "extended paths", such as `{{../foo/bar}}` (see below).
109
110 In order to process the "dotted names" of [Mustache v1.1.2](https://github.com/mustache/spec), such as `{{foo.bar}}`, you have to ask for it explicitely:
111
112 The recommended way is to call, prior to any rendering, the following method:
113
114 [GRMustache setDefaultTemplateOptions:GRMustacheTemplateOptionMustacheSpecCompatibility];
115 [GRMustacheTemplate renderObject:...] // will use Mustache v1.1.2 rendering
116
117 Since GRMustache 2 will stop using Handlebars as its default behavior, think of this line as something similar to Python's `from __future__ import ...` (see [PEP 236](http://www.python.org/dev/peps/pep-0236/)). When GRMustache hits version 2, it will be easier for you to migrate.
118
119 You may also take the explicit and more verbose path, and provide the `GRMustacheTemplateOptionMustacheSpecCompatibility` option to methods below.
120
121 enum {
122 // default, with support for extended paths of Handlebars.js
123 GRMustacheTemplateOptionNone = 0,
124
125 // support for the dotted names of Mustache v1.1.2
126 GRMustacheTemplateOptionMustacheSpecCompatibility = 0x01,
127 };
128
129 typedef NSUInteger GRMustacheTemplateOptions;
130
131 // Renders the provided templateString.
132 + (NSString *)renderObject:(id)object
133 fromString:(NSString *)templateString
134 options:(GRMustacheTemplateOptions)options
135 error:(NSError **)outError;
136
137 // Renders the template loaded from a url. (from MacOS 10.6 and iOS 4.0)
138 + (NSString *)renderObject:(id)object
139 fromContentsOfURL:(NSURL *)url
140 options:(GRMustacheTemplateOptions)options
141 error:(NSError **)outError;
142
143 // Renders the template loaded from a path.
144 + (NSString *)renderObject:(id)object
145 fromContentsOfFile:(NSString *)path
146 options:(GRMustacheTemplateOptions)options
147 error:(NSError **)outError;
148
149 // Renders the template loaded from a bundle resource of extension "mustache".
150 + (NSString *)renderObject:(id)object
151 fromResource:(NSString *)name
152 bundle:(NSBundle *)bundle
153 options:(GRMustacheTemplateOptions)options
154 error:(NSError **)outError;
155
156 // Renders the template loaded from a bundle resource of provided extension.
157 + (NSString *)renderObject:(id)object
158 fromResource:(NSString *)name
159 withExtension:(NSString *)ext
160 bundle:(NSBundle *)bundle
161 options:(GRMustacheTemplateOptions)options
162 error:(NSError **)outError;
163
164
165 ### Errors
166
167 GRMustache methods may return errors whose domain is GRMustacheErrorDomain.
168
169 extern NSString* const GRMustacheErrorDomain;
170
171 Their error codes may be interpreted with the GRMustacheErrorCode enumeration:
172
173 typedef enum {
174 GRMustacheErrorCodeParseError,
175 GRMustacheErrorCodeTemplateNotFound,
176 } GRMustacheErrorCode;
f01775d @groue README
authored
177
178 Compiling templates
179 -------------------
180
3c453f8 @groue typo
authored
181 If you are planning to render the same template multiple times, it is more efficient to parse it once, with the compiling methods of the GRMustacheTemplate class:
f01775d @groue README
authored
182
183 // Parses the templateString.
184 + (id)parseString:(NSString *)templateString
185 error:(NSError **)outError;
186
a1f2cf1 @groue v1.4.0
authored
187 // Loads and parses the template from url. (from MacOS 10.6 and iOS 4.0)
f01775d @groue README
authored
188 + (id)parseContentsOfURL:(NSURL *)url
189 error:(NSError **)outError;
190
a1f2cf1 @groue v1.4.0
authored
191 // Loads and parses the template from path.
192 + (id)parseContentsOfFile:(NSString *)path
193 error:(NSError **)outError;
194
f01775d @groue README
authored
195 // Loads and parses the template from a bundle resource of extension "mustache".
196 + (id)parseResource:(NSString *)name
197 bundle:(NSBundle *)bundle
198 error:(NSError **)outError;
199
200 // Loads and parses the template from a bundle resource of provided extension.
201 + (id)parseResource:(NSString *)name
202 withExtension:(NSString *)ext
203 bundle:(NSBundle *)bundle
204 error:(NSError **)outError;
205
3c453f8 @groue typo
authored
206 Those methods return GRMustacheTemplate instances, which render objects with the following method:
f01775d @groue README
authored
207
208 - (NSString *)renderObject:(id)object;
209
210 For instance:
211
212 // Compile template
213 GRMustacheTemplate *template = [GRMustacheTemplate parseString:@"Hi {{name}}!" error:nil];
214 // @"Hi Mom!"
215 [template renderObject:[NSDictionary dictionaryWithObject:@"Mom" forKey:@"name"]];
216 // @"Hi Dad!"
217 [template renderObject:[NSDictionary dictionaryWithObject:@"Dad" forKey:@"name"]];
218 // @"Hi !"
219 [template renderObject:nil];
c4a85a4 @groue documentation
authored
220 // @"Hi !", shortcut to renderObject:nil
221 [template render];
f01775d @groue README
authored
222
18dc85c @groue v1.8.0
authored
223 All those methods return templates that are compatible with [Handlebars.js](https://github.com/wycats/handlebars.js) and its "extended paths", such as `{{../foo/bar}}` (see below).
224
225 In order to process the "dotted names" of [Mustache v1.1.2](https://github.com/mustache/spec), such as `{{foo.bar}}`, you have to ask for it explicitely. See "Rendering methods" above.
226
f01775d @groue README
authored
227 Context objects
228 ---------------
229
230 You will provide a rendering method with a context object.
231
0512696 @oalders Very small changes in language.
oalders authored
232 Mustache tag names are looked for in the context object, through the standard Key-Value Coding method `valueForKey:`.
f01775d @groue README
authored
233
0542e1d @groue Tests for GRMustacheContext class + No more GRMustacheContext protocol
authored
234 The most obvious objects which support KVC are dictionaries. You may also provide with any other object:
f01775d @groue README
authored
235
0542e1d @groue Tests for GRMustacheContext class + No more GRMustacheContext protocol
authored
236 @interface Person: NSObject
f01775d @groue README
authored
237 + (id)personWithName:(NSString *)name;
238 - (NSString *)name;
239 @end
240
241 // returns @"Hi Mom!"
242 [GRMustacheTemplate renderObject:[Person personWithName:@"Mom"]
243 fromString:@"Hi {{name}}!"
244 error:nil];
245
ef2f187 @groue Avoid the NSUndefinedKeyException attack
authored
246 A KVC key miss can raise a NSUndefinedKeyException. GRMustache catches those exceptions:
2d7c305 @groue A word about KVC key misses
authored
247
ef2f187 @groue Avoid the NSUndefinedKeyException attack
authored
248 // doesn't raise, and returns @"Hi !"
2d7c305 @groue A word about KVC key misses
authored
249 [GRMustacheTemplate renderObject:[Person personWithName:@"Mom"]
ef2f187 @groue Avoid the NSUndefinedKeyException attack
authored
250 fromString:@"Hi {{XXX}}!"
2d7c305 @groue A word about KVC key misses
authored
251 error:nil];
252
7789aa7 @groue NSUndefinedKeyException attack topic has moved from README to wiki
authored
253 Those exceptions are part of the regular rendering of a template. Yet, when debugging your project, they may become an annoyance. Check the [Avoid the NSUndefinedKeyException attack](https://github.com/groue/GRMustache/wiki/Avoid-the-NSUndefinedKeyException-attack) wiki page.
ef2f187 @groue Avoid the NSUndefinedKeyException attack
authored
254
f01775d @groue README
authored
255 Tag types
256 ---------
257
258 We'll now cover all mustache tag types, and how they are rendered.
259
c81b716 @groue Clarification on what is a *false* value
authored
260 But let's give some definitions first:
261
efbfc9b @groue Clearer sections documentation
authored
262 - GRMustache considers *enumerable* all objects conforming to the NSFastEnumeration protocol, but NSDictionary. The most obvious enumerable is NSArray.
c81b716 @groue Clarification on what is a *false* value
authored
263
a6a76e0 @groue documentation: false values include [NSNumber numberWithBool:NO]
authored
264 - GRMustache considers *false* KVC key misses, and the following values: `nil`, `[NSNull null]`, `[NSNumber numberWithBool:NO]`, `kCFBooleanFalse`, and the empty string `@""`.
c81b716 @groue Clarification on what is a *false* value
authored
265
d264f3d @groue Booleans topic has moved from README to wiki
authored
266 The topic of booleans is not trivial. Check the [Booleans](https://github.com/groue/GRMustache/wiki/Booleans) wiki page.
267
f01775d @groue README
authored
268 ### Comments `{{!...}}`
269
270 Comments tags are not rendered.
271
272 ### Variable tags `{{name}}`
273
274 Such a tag is rendered according to the value for key `name` in the context.
275
efbfc9b @groue Clearer sections documentation
authored
276 If the value is *false*, the tag is not rendered.
f01775d @groue README
authored
277
3c453f8 @groue typo
authored
278 Otherwise, it is rendered with the regular string description of the value, HTML escaped.
f01775d @groue README
authored
279
280 ### Unescaped variable tags `{{{name}}}` and `{{&name}}`
281
282 Such a tag is rendered according to the value for key `name` in the context.
283
efbfc9b @groue Clearer sections documentation
authored
284 If the value is *false*, the tag is not rendered.
f01775d @groue README
authored
285
3c453f8 @groue typo
authored
286 Otherwise, it is rendered with the regular string description of the value, without HTML escaping.
f01775d @groue README
authored
287
efbfc9b @groue Clearer sections documentation
authored
288 ### Sections `{{#name}}...{{/name}}`
f01775d @groue README
authored
289
efbfc9b @groue Clearer sections documentation
authored
290 Sections are rendered differently, depending on the value for key `name` in the context:
f01775d @groue README
authored
291
efbfc9b @groue Clearer sections documentation
authored
292 #### False sections
f01775d @groue README
authored
293
efbfc9b @groue Clearer sections documentation
authored
294 If the value is *false*, the section is not rendered.
295
d264f3d @groue Booleans topic has moved from README to wiki
authored
296 The topic of booleans is not trivial. Check the [Booleans](https://github.com/groue/GRMustache/wiki/Booleans) wiki page.
297
efbfc9b @groue Clearer sections documentation
authored
298 #### Enumerable sections
299
b0976e4 @groue Samples
authored
300 If the value is *enumerable*, the text between the `{{#name}}` and `{{/name}}` tags is rendered once for each item in the enumerable.
301
302 Each item becomes the context while being rendered. This is how you iterate over a collection of objects:
efbfc9b @groue Clearer sections documentation
authored
303
b0976e4 @groue Samples
authored
304 My shopping list:
305 {{#items}}
306 - {{name}}
307 {{/items}}
308
0512696 @oalders Very small changes in language.
oalders authored
309 When a key is missed at the item level, it is looked for in the enclosing context.
efbfc9b @groue Clearer sections documentation
authored
310
18dc85c @groue v1.8.0
authored
311 #### Lambda sections
efbfc9b @groue Clearer sections documentation
authored
312
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
313 Read below "Helpers", which covers in detail how GRMustache allows you to provide custom code for rendering sections.
5b5cbba @groue helpers API stabilization
authored
314
efbfc9b @groue Clearer sections documentation
authored
315 #### Other sections
f01775d @groue README
authored
316
18dc85c @groue v1.8.0
authored
317 Otherwise - if the value is not enumerable, false, or lambda - the content of the section is rendered once.
b0976e4 @groue Samples
authored
318
319 The value becomes the context while being rendered. This is how you traverse an object hierarchy:
320
321 {{#me}}
322 {{#mother}}
323 {{#father}}
324 My mother's father was named {{name}}.
325 {{/father}}
326 {{/mother}}
327 {{/me}}
328
0512696 @oalders Very small changes in language.
oalders authored
329 When a key is missed, it is looked for in the enclosing context. This is the base mechanism for templates like:
b0976e4 @groue Samples
authored
330
331 {{! If there is a title, render it in a <h1> tag }}
332 {{#title}}
333 <h1>{{title}}</h1>
334 {{/title}}
f01775d @groue README
authored
335
336 ### Inverted sections `{{^name}}...{{/name}}`
337
b0976e4 @groue Samples
authored
338 Such a section is rendered when the `{{#name}}...{{/name}}` section would not: in the case of false values, or empty enumerables.
f01775d @groue README
authored
339
5ccdc13 @groue Documentation for extended paths and dot-key
authored
340 ### Partials `{{>partial_name}}`
f01775d @groue README
authored
341
5ccdc13 @groue Documentation for extended paths and dot-key
authored
342 A `{{>partial_name}}` tag is rendered as a partial loaded from the file system.
f01775d @groue README
authored
343
5c144ba @groue More GRMustacheTemplateLoader documentation in README
authored
344 Partials must have the same extension as their including template.
f01775d @groue README
authored
345
5c144ba @groue More GRMustacheTemplateLoader documentation in README
authored
346 Recursive partials are possible. Just avoid infinite loops in your context objects.
347
0512696 @oalders Very small changes in language.
oalders authored
348 Depending on the method which has been used to create the original template, partials will be looked for in different places :
f01775d @groue README
authored
349
e38d680 @groue Public [GRMustacheTemplateLoader templateLoaderWithCurrentWorkingDirecto...
authored
350 - In the main bundle:
f01775d @groue README
authored
351 - `renderObject:fromString:error:`
352 - `parseString:error:`
e38d680 @groue Public [GRMustacheTemplateLoader templateLoaderWithCurrentWorkingDirecto...
authored
353 - In the specified bundle:
f01775d @groue README
authored
354 - `renderObject:fromResource:bundle:error:`
355 - `renderObject:fromResource:withExtension:bundle:error:`
356 - `parseResource:bundle:error:`
357 - `parseResource:withExtension:bundle:error:`
e38d680 @groue Public [GRMustacheTemplateLoader templateLoaderWithCurrentWorkingDirecto...
authored
358 - Relatively to the URL of the including template:
359 - `renderObject:fromContentsOfURL:error:`
360 - `parseContentsOfURL:error:`
a1f2cf1 @groue v1.4.0
authored
361 - Relatively to the path of the including template:
362 - `renderObject:fromContentsOfFile:error:`
363 - `parseContentsOfFile:error:`
f01775d @groue README
authored
364
137fd2d @groue GRMustacheTemplateLoader documentation goes in its own "Template loaders...
authored
365 The "Template loaders" section below will show you more partial loading GRMustache features.
2abb4b7 @groue GRMustacheTemplateLoader enters README
authored
366
18dc85c @groue v1.8.0
authored
367 Implicit iterator, dotted names and extended paths
368 --------------------------------------------------
369
370 ### Implicit iterator
371
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
372 The dot "`.`" stands for the current context itself. This "implicit iterator" can be useful when iterating a list of scalar objects. For instance, the following context:
18dc85c @groue v1.8.0
authored
373
374 context = [NSDictionary dictionaryWithObject:[NSArray arrayWithObjects: @"beer", @"ham", nil]
375 forKey:@"item"];
376
377 renders:
378
379 <ul><li>beer</li><li>ham</li></ul>
380
381 when applied to the template:
382
383 <ul>{{#item}}<li>{{.}}</li>{{/item}}</ul>
5ccdc13 @groue Documentation for extended paths and dot-key
authored
384
385 ### Extended paths
386
387 GRMustache supports extended paths introduced by [Handlebars.js](https://github.com/wycats/handlebars.js). Paths are made up of typical expressions and / characters. Expressions allow you to not only display data from the current context, but to display data from contexts that are descendents and ancestors of the current context.
388
18dc85c @groue v1.8.0
authored
389 To display data from descendent contexts, use the `/` character. So, for example, if your context were structured like:
5ccdc13 @groue Documentation for extended paths and dot-key
authored
390
391 context = [NSDictionary dictionaryWithObjectsAndKeys:
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
392 [Person personWithName:@"Alan"], @"person",
5ccdc13 @groue Documentation for extended paths and dot-key
authored
393 [Company companyWithName:@"Acme"], @"company",
394 nil];
395
396 you could display the person's name from the top-level context with the following expression:
397
398 {{person/name}}
399
400 Similarly, if already traversed into the person object you could still display the company's name with an expression like ``{{../company/name}}`, so:
401
402 {{#person}}{{name}} - {{../company/name}}{{/person}}
403
404 would render:
405
406 Alan - Acme
407
18dc85c @groue v1.8.0
authored
408 ### Dotted names
5ccdc13 @groue Documentation for extended paths and dot-key
authored
409
18dc85c @groue v1.8.0
authored
410 GRMustache supports the dotted names of [Mustache v1.1.2](https://github.com/mustache/spec). Dotted names are made up of typical names and . characters. Expressions allow you to not only display data from the current context, but to display data from contexts that are descendents of the current context.
5ccdc13 @groue Documentation for extended paths and dot-key
authored
411
18dc85c @groue v1.8.0
authored
412 To display data from descendent contexts, use the `.` character. So, for example, if your context were structured like:
5ccdc13 @groue Documentation for extended paths and dot-key
authored
413
18dc85c @groue v1.8.0
authored
414 context = [NSDictionary dictionaryWithObjectsAndKeys:
415 [Person personWithName:@"Alan"], @"person",
416 nil];
5ccdc13 @groue Documentation for extended paths and dot-key
authored
417
18dc85c @groue v1.8.0
authored
418 you could display the person's name from the top-level context with the following expression:
5ccdc13 @groue Documentation for extended paths and dot-key
authored
419
18dc85c @groue v1.8.0
authored
420 {{person.name}}
5ccdc13 @groue Documentation for extended paths and dot-key
authored
421
18dc85c @groue v1.8.0
authored
422 You have to explicitely ask for the Mustache spec compatibility in order to use dotted names. See "Rendering methods" above.
5ccdc13 @groue Documentation for extended paths and dot-key
authored
423
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
424 Helpers
3de3613 @groue v1.5.0
authored
425 -------
5b5cbba @groue helpers API stabilization
authored
426
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
427 Mustache helpers, also known as lambdas, allow you to execute custom code when rendering a mustache section such as:
5b5cbba @groue helpers API stabilization
authored
428
85657a2 @groue Improved lambdas documentation
authored
429 {{#name}}...{{/name}}
5b5cbba @groue helpers API stabilization
authored
430
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
431 For the purpose of demonstration, we'll implement a helper that translates, via `NSLocalizedString`, the content of the section: one will expect `{{#localize}}Delete{{/localize}}` to output `Effacer` when the locale is French.
5b5cbba @groue helpers API stabilization
authored
432
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
433 We'll see three techniques for implementing the behavior.
5b5cbba @groue helpers API stabilization
authored
434
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
435 ### Implementing helpers with specific selectors
5b5cbba @groue helpers API stabilization
authored
436
85657a2 @groue Improved lambdas documentation
authored
437 If the context used for mustache rendering implements the `localizeSection:withContext:` selector (generally, a method whose name is the name of the section, to which you append `Section:withContext:`), then this method will be called when rendering the section.
5b5cbba @groue helpers API stabilization
authored
438
85657a2 @groue Improved lambdas documentation
authored
439 The choice of the class that should implement this selector is up to you, as long as it can be reached when rendering the template, just as regular values.
5b5cbba @groue helpers API stabilization
authored
440
85657a2 @groue Improved lambdas documentation
authored
441 For instance, let's focus on the following template snippet:
5b5cbba @groue helpers API stabilization
authored
442
85657a2 @groue Improved lambdas documentation
authored
443 {{#cart}}
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
444 {{#items}}
445 {{quantity}} × {{name}}
446 {{#localize}}Delete{{/localize}}
447 {{/items}}
85657a2 @groue Improved lambdas documentation
authored
448 {{/cart}}
5b5cbba @groue helpers API stabilization
authored
449
85657a2 @groue Improved lambdas documentation
authored
450 When the `localize` section is rendered, the context contains an item object, an items collection, a cart object, plus any surrounding objects.
d63419a @groue more lambda and helpers documentation
authored
451
85657a2 @groue Improved lambdas documentation
authored
452 If the item object implements the `localizeSection:withContext:` selector, then its implementation will be called. Otherwise, the selector will be looked up in the items collection. Since this collection is likely an `NSArray` instance, the lookup will continue with the cart and its surrounding context, until some object is found that implements the `localizeSection:withContext:` selector.
5b5cbba @groue helpers API stabilization
authored
453
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
454 In order to have a reusable `localize` helper, we'll isolate it in a specific class, `MustacheHelper`, and make sure this helper is provided to GRMustache when rendering our template.
5b5cbba @groue helpers API stabilization
authored
455
85657a2 @groue Improved lambdas documentation
authored
456 Let's first declare our helper class:
df2bdc8 @groue Fully expose and document GRMustacheContext
authored
457
85657a2 @groue Improved lambdas documentation
authored
458 @interface MustacheHelper: NSObject
909362d @groue more documentation about helper methods
authored
459
85657a2 @groue Improved lambdas documentation
authored
460 Since our helper doesn't carry any state, let's declare our `localizeSection:withContext:` selector as a class method:
5b5cbba @groue helpers API stabilization
authored
461
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
462 + (NSString *)localizeSection:(GRMustacheSection *)section withContext:(id)context;
85657a2 @groue Improved lambdas documentation
authored
463 @end
5b5cbba @groue helpers API stabilization
authored
464
85657a2 @groue Improved lambdas documentation
authored
465 #### The literal inner content
909362d @groue more documentation about helper methods
authored
466
85657a2 @groue Improved lambdas documentation
authored
467 Now up to the first implementation. The _section_ argument is a `GRMustacheSection` object, which represents the section being rendered: `{{#localize}}Delete{{/localize}}`.
2f48189 @groue deprecate GRMustacheLambdaMake
authored
468
ec0ea1c @groue typo
authored
469 This _section_ object has a `templateString` property, which returns the literal inner content of the section. It will return `@"Delete"` in our specific example. This looks like a perfect argument for `NSLocalizedString`:
2f48189 @groue deprecate GRMustacheLambdaMake
authored
470
85657a2 @groue Improved lambdas documentation
authored
471 @implementation MustacheHelper
472 + (NSString *)localizeSection:(GRMustacheSection *)section withContext:(id)context
473 {
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
474 return NSLocalizedString(section.templateString, nil);
85657a2 @groue Improved lambdas documentation
authored
475 }
476 @end
ae73315 @groue more lambda and helpers documentation
authored
477
85657a2 @groue Improved lambdas documentation
authored
478 So far, so good, this would work as expected.
ae73315 @groue more lambda and helpers documentation
authored
479
85657a2 @groue Improved lambdas documentation
authored
480 #### Rendering the inner content
909362d @groue more documentation about helper methods
authored
481
85657a2 @groue Improved lambdas documentation
authored
482 Yet the application keeps on evolving, and it appears that the item names should also be localized. The template snippet now reads:
2f48189 @groue deprecate GRMustacheLambdaMake
authored
483
85657a2 @groue Improved lambdas documentation
authored
484 {{#cart}}
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
485 {{#items}}
486 {{quantity}} × {{#localize}}{{name}}{{/localize}}
487 {{#localize}}Delete{{/localize}}
488 {{/items}}
85657a2 @groue Improved lambdas documentation
authored
489 {{/cart}}
909362d @groue more documentation about helper methods
authored
490
85657a2 @groue Improved lambdas documentation
authored
491 Now the strings we have to localize may be:
909362d @groue more documentation about helper methods
authored
492
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
493 - literal strings from the template: `Delete`
494 - strings coming from cart items : `{{name}}`
85657a2 @groue Improved lambdas documentation
authored
495
496 Our first `MustacheHelper` will fail, since it will return `NSLocalizedString(@"{{name}}", nil)` when localizing item names.
497
498 Actually we now need to feed `NSLocalizedString` with the _rendering_ of the inner content, not the _literal_ inner content.
499
500 Fortunately, we have:
501
502 - the `renderObject:` method of `GRMustacheSection`, which renders the content of the receiver with the provided object.
503 - the _context_ parameter, which is the current rendering context, containing a cart item, an item collection, a cart, and any surrouding objects.
504
505 `[section renderObject:context]` is exactly what we need: the inner content rendered in the current context.
506
507 Now we can fix our implementation:
508
509 @implementation MustacheHelper
510 + (NSString *)localizeSection:(GRMustacheSection *)section withContext:(id)context
0915e91 @groue v1.4.1
authored
511 {
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
512 NSString *renderedContent = [section renderObject:context];
513 return NSLocalizedString(renderedContent, nil);
2f48189 @groue deprecate GRMustacheLambdaMake
authored
514 }
515 @end
516
85657a2 @groue Improved lambdas documentation
authored
517 #### Using the helper object
2f48189 @groue deprecate GRMustacheLambdaMake
authored
518
85657a2 @groue Improved lambdas documentation
authored
519 Now that our helper class is well defined, let's use it.
2f48189 @groue deprecate GRMustacheLambdaMake
authored
520
85657a2 @groue Improved lambdas documentation
authored
521 Assuming:
2f48189 @groue deprecate GRMustacheLambdaMake
authored
522
85657a2 @groue Improved lambdas documentation
authored
523 - `orderConfirmation.mustache` is a mustache template resource,
524 - `self` has a `cart` property suitable for our template rendering,
2f48189 @groue deprecate GRMustacheLambdaMake
authored
525
85657a2 @groue Improved lambdas documentation
authored
526 Let's first parse the template:
2f48189 @groue deprecate GRMustacheLambdaMake
authored
527
85657a2 @groue Improved lambdas documentation
authored
528 GRMustacheTemplate *template = [GRMustacheTemplate parseResource:@"orderConfirmation" bundle:nil error:NULL];
5b5cbba @groue helpers API stabilization
authored
529
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
530 Let's now render, with two objects: our `MustacheHelper` class that will provide the `localize` helper, and `self` that will provide the `cart`:
5b5cbba @groue helpers API stabilization
authored
531
85657a2 @groue Improved lambdas documentation
authored
532 [template renderObjects:[MustacheHelper class], self, nil];
0915e91 @groue v1.4.1
authored
533
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
534 ### Implementing helpers with blocks
0915e91 @groue v1.4.1
authored
535
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
536 Starting MacOS6 and iOS4, blocks are available to the Objective-C language. GRMustache provides a block-based helper API.
85657a2 @groue Improved lambdas documentation
authored
537
538 This technique does not involve declaring any special selector. But when asked for the `localized` key, your context will return a GRMustacheBlockHelper instance, built in the same fashion as the helper methods seen above:
5b5cbba @groue helpers API stabilization
authored
539
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
540 id localizeHelper = [GRMustacheBlockHelper helperWithBlock:(^(GRMustacheSection *section, id context) {
541 NSString *renderedContent = [section renderObject:context];
542 return NSLocalizedString(renderedContent, nil);
85657a2 @groue Improved lambdas documentation
authored
543 }];
5b5cbba @groue helpers API stabilization
authored
544
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
545 See how the block implementation is strictly identical to the helper method discussed above.
5b5cbba @groue helpers API stabilization
authored
546
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
547 Actually, your only concern is to make sure your values and helper code can be reached by GRMustache when rendering your templates. Implementing `localizeSection:withContext` or returning a GRMustacheBlockHelper instance for the `localize` key is strictly equivalent.
5b5cbba @groue helpers API stabilization
authored
548
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
549 However, unlike the selector technique seen above, our code is not yet bound to the section name, `localize`. And actually, we need some container object. Let's go with a dictionary:
ae73315 @groue more lambda and helpers documentation
authored
550
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
551 id mustacheHelper = [NSDictionary dictionaryWithObject:localizeHelper forKey:@"localize"];
df2bdc8 @groue Fully expose and document GRMustacheContext
authored
552
85657a2 @groue Improved lambdas documentation
authored
553 And now the rendering is done as usual:
df2bdc8 @groue Fully expose and document GRMustacheContext
authored
554
85657a2 @groue Improved lambdas documentation
authored
555 [template renderObjects:mustacheHelper, self, nil];
227231f @groue sample lambda with NSLocalizedString
authored
556
85657a2 @groue Improved lambdas documentation
authored
557
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
558 ### Implementing helpers with classes conforming to the `GRMustacheHelper` protocol
559
560 Now that we have a nice working localizing helper, we may well want to reuse it in some other projects. Unfortunately, the two techniques seen above don't help us that much acheiving this goal:
561
562 - the selector technique binds the helper code to the section name, thus making impossible to share the helper code between various sections of various templates.
563 - the block technique provides no way to cleanly encapsulate the helper code.
564
565 The `GRMustacheHelper` protocol aims at giving you a way to create classes which encapsulate a helper.
566
567 In our case, here would be the implementation of our localizing helper:
568
569 @interface LocalizedStringHelper: NSObject<GRMustacheHelper>
570 @end
571
572 @implementation LocalizedStringHelper
573 // The renderSection:inContext method is required by the GRMustacheHelper protocol
574 - (NSString *)renderSection:(GRMustacheSection *)section withContext:(id)context
575 {
576 NSString *renderedContent = [section renderObject:context];
577 return NSLocalizedString(renderedContent, nil);
578 }
579 @end
580
581 We, again, need some container object, in order to attach our helper to the `localize` key:
582
583 LocalizedStringHelper *localizeHelper = [[[LocalizedStringHelper alloc] init] autorelease];
584 id mustacheHelper = [NSDictionary dictionaryWithObject:localizeHelper forKey:@"localize"];
585
586 And now the rendering is done as usual:
587
588 [template renderObjects:mustacheHelper, self, nil];
589
590 Speaking of encapsulation, our `LocalizedStringHelper` can even now support localization tables. This is left as an exercise for the reader :-)
85657a2 @groue Improved lambdas documentation
authored
591
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
592 ### Usages of helpers
85657a2 @groue Improved lambdas documentation
authored
593
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
594 Helpers can be used for whatever you may find relevant.
227231f @groue sample lambda with NSLocalizedString
authored
595
596 You may implement caching:
df2bdc8 @groue Fully expose and document GRMustacheContext
authored
597
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
598 - (NSString *)renderSection:(GRMustacheSection *)section withContext:(id)context {
779d22b @groue rewrite helper method samples
authored
599 if (self.cache == nil) { self.cache = [section renderObject:context]; }
600 return self.cache;
601 };
df2bdc8 @groue Fully expose and document GRMustacheContext
authored
602
779d22b @groue rewrite helper method samples
authored
603 You may render an extended context:
df2bdc8 @groue Fully expose and document GRMustacheContext
authored
604
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
605 - (NSString *)renderSection:(GRMustacheSection *)section withContext:(id)context {
3de3613 @groue v1.5.0
authored
606 return [section renderObjects:context, ...];
df2bdc8 @groue Fully expose and document GRMustacheContext
authored
607 });
608
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
609 You may render a totally different context (note that this is the base technique for the GRMustacheNumberFormatterHelper and GRMustacheDateFormatterHelper helpers that ship with GRMustache):
df2bdc8 @groue Fully expose and document GRMustacheContext
authored
610
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
611 - (NSString *)renderSection:(GRMustacheSection *)section withContext:(id)context {
612 return [section renderObject:...];
df2bdc8 @groue Fully expose and document GRMustacheContext
authored
613 });
614
615 You may implement debugging sections:
616
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
617 - (NSString *)renderSection:(GRMustacheSection *)section withContext:(id)context {
df2bdc8 @groue Fully expose and document GRMustacheContext
authored
618 NSLog(section.templateString); // log the unrendered section
619 NSLog([section renderObject:context]); // log the rendered section
620 return nil; // don't render anything
621 });
622
623
f52da9d @groue README+RELEASE_NOTES for GRMustacheNumberFormatterHelper and GRMustacheD...
authored
624 Utils
625 -----
626
627 GRMustache ships with a few helper classes. They do not belong the the core GRMustache code, and as such must be imported separately:
628
629 #import "GRMustacheUtils.h"
630
631 ### GRMustacheNumberFormatterHelper
632
633 This helper allows you to format *all* numbers in a section of your template.
634
635 For instance, given the following template:
636
637 raw: {{float}}
638
639 {{#percent_format}}
640 percent: {{float}}
641 {{/percent_format}}
642
643 {{#decimal_format}}
644 decimal: {{float}}
645 {{/decimal_format}}
646
647 The float value would be displayed as a percentage in the `percent_format` section, and as a decimal in the `decimal_format` section.
648
649 We just have to create two `GRMustacheNumberFormatterHelper` objects, provide them with `NSNumberFormatter` instances, and attach them to the section names:
650
651 #import "GRMustacheUtils.h"
652
653 // The percent formatter, and helper:
654 NSNumberFormatter percentNumberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
655 percentNumberFormatter.numberStyle = kCFNumberFormatterPercentStyle;
656 GRMustacheNumberFormatterHelper *percentHelper = [GRMustacheNumberFormatterHelper helperWithNumberFormatter:percentNumberFormatter];
657
658 // The decimal formatter, and helper:
659 NSNumberFormatter decimalNumberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
660 decimalNumberFormatter.numberStyle = kCFNumberFormatterDecimalStyle;
661 GRMustacheNumberFormatterHelper *decimalHelper = [GRMustacheNumberFormatterHelper helperWithNumberFormatter:decimalNumberFormatter];
662
663 // The rendered data:
664 NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:
665 percentHelper, @"percent_format",
666 decimalHelper, @"decimal_format",
667 [NSNumber numberWithFloat:0.5f], @"float",
668 nil];
669
670 // The final rendering (on a French system):
671 // raw: 0.5
672 // percent: 50 %
673 // decimal: 0,5
674 [template renderObject:data];
675
676 It is worth noting that the `GRMustacheNumberFormatterHelper` is implemented on top of public GRMustache APIs. Check the code for inspiration.
677
678 ### GRMustacheDateFormatterHelper
679
680 This helper allows you to format *all* dates in a section of your template.
681
682 Read the `GRMustacheNumberFormatterHelper` documentation above, because the principles are the same. You'll just provide a `NSDateFormatter` instead of a `NSNumberFormatter`.
683
137fd2d @groue GRMustacheTemplateLoader documentation goes in its own "Template loaders...
authored
684 Template loaders
685 ----------------
686
687 ### Fine tuning loading of templates
688
18dc85c @groue v1.8.0
authored
689 The GRMustacheTemplateLoader class is able to load templates and their partials from anywhere.
690
691 The [Implementing your own template loading strategy](https://github.com/groue/GRMustache/wiki/Implementing-your-own-template-loading-strategy) wiki page will tell you how to subclass GRMustacheTemplateLoader in order to load templates and partials from an NSDictionary.
692
693 The GRMustacheTemplateLoader class itself is able to load templates and their partials from anywhere in the file system, and provides more options than the high-level methods already seen.
137fd2d @groue GRMustacheTemplateLoader documentation goes in its own "Template loaders...
authored
694
0512696 @oalders Very small changes in language.
oalders authored
695 You may instantiate one with the following GRMustacheTemplateLoader class methods:
137fd2d @groue GRMustacheTemplateLoader documentation goes in its own "Template loaders...
authored
696
a1f2cf1 @groue v1.4.0
authored
697 // Loads templates and partials from a directory, with "mustache" extension, encoded in UTF8 (from MacOS 10.6 and iOS 4.0)
137fd2d @groue GRMustacheTemplateLoader documentation goes in its own "Template loaders...
authored
698 + (id)templateLoaderWithBaseURL:(NSURL *)url;
699
a1f2cf1 @groue v1.4.0
authored
700 // Loads templates and partials from a directory, with provided extension, encoded in UTF8 (from MacOS 10.6 and iOS 4.0)
137fd2d @groue GRMustacheTemplateLoader documentation goes in its own "Template loaders...
authored
701 + (id)templateLoaderWithBaseURL:(NSURL *)url
702 extension:(NSString *)ext;
703
a1f2cf1 @groue v1.4.0
authored
704 // Loads templates and partials from a directory, with provided extension, encoded in provided encoding (from MacOS 10.6 and iOS 4.0)
137fd2d @groue GRMustacheTemplateLoader documentation goes in its own "Template loaders...
authored
705 + (id)templateLoaderWithBaseURL:(NSURL *)url
706 extension:(NSString *)ext
707 encoding:(NSStringEncoding)encoding;
708
a1f2cf1 @groue v1.4.0
authored
709 // Loads templates and partials from a directory, with "mustache" extension, encoded in UTF8
6b1dbf7 @groue v1.6.0
authored
710 + (id)templateLoaderWithDirectory:(NSString *)path;
a1f2cf1 @groue v1.4.0
authored
711
712 // Loads templates and partials from a directory, with provided extension, encoded in UTF8
6b1dbf7 @groue v1.6.0
authored
713 + (id)templateLoaderWithDirectory:(NSString *)path
714 extension:(NSString *)ext;
a1f2cf1 @groue v1.4.0
authored
715
716 // Loads templates and partials from a directory, with provided extension, encoded in provided encoding
6b1dbf7 @groue v1.6.0
authored
717 + (id)templateLoaderWithDirectory:(NSString *)path
718 extension:(NSString *)ext
719 encoding:(NSStringEncoding)encoding;
a1f2cf1 @groue v1.4.0
authored
720
137fd2d @groue GRMustacheTemplateLoader documentation goes in its own "Template loaders...
authored
721 // Loads templates and partials from a bundle, with "mustache" extension, encoded in UTF8
722 + (id)templateLoaderWithBundle:(NSBundle *)bundle;
723
724 // Loads templates and partials from a bundle, with provided extension, encoded in UTF8
725 + (id)templateLoaderWithBundle:(NSBundle *)bundle
726 extension:(NSString *)ext;
727
728 // Loads templates and partials from a bundle, with provided extension, encoded in provided encoding
729 + (id)templateLoaderWithBundle:(NSBundle *)bundle
730 extension:(NSString *)ext
731 encoding:(NSStringEncoding)encoding;
732
733 Once you have a GRMustacheTemplateLoader object, you may load a template from its location:
734
735 GRMustacheTemplate *template = [loader parseTemplateNamed:@"document" error:nil];
736
737 You may also have the loader parse a template string. Only partials would then be loaded from the loader's location:
738
739 GRMustacheTemplate *template = [loader parseString:@"..." error:nil];
740
741 The rendering is done as usual:
742
743 NSString *rendering = [template renderObject:...];
744
f01775d @groue README
authored
745
18dc85c @groue v1.8.0
authored
746 All those template loaders return templates that are compatible with [Handlebars.js](https://github.com/wycats/handlebars.js) and its "extended paths", such as `{{../foo/bar}}` (see below).
f01775d @groue README
authored
747
18dc85c @groue v1.8.0
authored
748 In order to process the "dotted names" of [Mustache v1.1.2](https://github.com/mustache/spec), such as `{{foo.bar}}`, you have to ask for it explicitely. See "Rendering methods" above.
f01775d @groue README
authored
749
a674b13 @groue README.md: added "a practical example" section
authored
750
b0976e4 @groue Samples
authored
751 A less simple example
752 ---------------------
a674b13 @groue README.md: added "a practical example" section
authored
753
3c453f8 @groue typo
authored
754 Let's be totally mad, and display a list of people and their birthdates in a UIWebView embedded in our iOS application.
a674b13 @groue README.md: added "a practical example" section
authored
755
3c453f8 @groue typo
authored
756 We'll most certainly have a UIViewController for displaying the web view:
a674b13 @groue README.md: added "a practical example" section
authored
757
758 @interface PersonListViewController: UIViewController
759 @property (nonatomic, retain) NSArray *persons;
760 @property (nonatomic, retain) IBOutlet UIWebView *webView;
761 @end
762
3c453f8 @groue typo
authored
763 The `persons` array contains some instances of our Person model:
a674b13 @groue README.md: added "a practical example" section
authored
764
765 @interface Person: NSObject
766 @property (nonatomic, retain) NSString *name;
767 @property (nonatomic, retain) NSDate *birthdate;
768 @end
769
3c453f8 @groue typo
authored
770 A PersonListViewController instance and its array of persons is a graph of objects that is already perfectly suitable for rendering our template:
a674b13 @groue README.md: added "a practical example" section
authored
771
772 PersonListViewController.mustache:
773
774 <html>
775 <body>
776 <dl>
777 {{#persons}}
778 <dt>{{name}}</dt>
779 <dd>{{localizedBirthdate}}</dd>
780 {{/persons}}
781 </dl>
782 </body>
783 </html>
784
56b7c37 @groue wording
authored
785 We already see the match between our classes' properties, and the `persons` and `name` keys. More on the `birthdate` vs. `localizedBirthdate` later.
a674b13 @groue README.md: added "a practical example" section
authored
786
787 We should already be able to render most of our template:
788
789 @implementation PersonListViewController
790 - (void)viewWillAppear:(BOOL)animated {
791 // Let's use self as the rendering context:
792 NSString *html = [GRMustacheTemplate renderObject:self
793 fromResource:@"PersonListViewController"
794 bundle:nil
795 error:nil];
796 [self.webView loadHTMLString:html baseURL:nil];
797 }
798 @end
799
800 Now our `{{#persons}}` enumerable section and `{{name}}` variable tag will perfectly render.
801
802 What about the `{{localizedBirthdate}}` tag?
803
804 Since we don't want to pollute our nice and clean Person model, let's add a category to it:
805
842f3b3 @groue Opaque context public API
authored
806 @interface Person(GRMustache)
a674b13 @groue README.md: added "a practical example" section
authored
807 @end
808
809 static NSDateFormatter *dateFormatter = nil;
842f3b3 @groue Opaque context public API
authored
810 @implementation Person(GRMustache)
a674b13 @groue README.md: added "a practical example" section
authored
811 - (NSString *)localizedBirthdate {
812 if (dateFormatter == nil) {
813 dateFormatter = [[NSDateFormatter alloc] init];
814 [dateFormatter setDateStyle:NSDateFormatterLongStyle];
815 [dateFormatter setTimeStyle:NSDateFormatterNoStyle];
816 }
817 return [dateFormatter stringFromDate:date];
818 }
819 @end
820
821 And we're ready to go!
822
e4bd74e @groue License
authored
823 License
824 -------
825
826 Released under the [MIT License](http://en.wikipedia.org/wiki/MIT_License)
827
828 Copyright (c) 2010 Gwendal Roué
829
830 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
831
832 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
833
834 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
835
Something went wrong with that request. Please try again.