Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 453 lines (296 sloc) 11.021 kb
f0857e5 @defunkt rtemplate => mustache
defunkt authored
1 Mustache
6ee6bcf @defunkt first draft
defunkt authored
2 =========
3
02edd2c @defunkt references make the first paragraph it read easier
defunkt authored
4 Inspired by [ctemplate][1] and [et][2], Mustache is a
5 framework-agnostic way to render logic-free views.
6ee6bcf @defunkt first draft
defunkt authored
6
b32c566 @defunkt quote ctemplates
defunkt authored
7 As ctemplates says, "It emphasizes separating logic from presentation:
8 it is impossible to embed application logic in this template language."
3aad2f3 @defunkt docs
defunkt authored
9
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
10
3aad2f3 @defunkt docs
defunkt authored
11 Overview
12 --------
13
f0857e5 @defunkt rtemplate => mustache
defunkt authored
14 Think of Mustache as a replacement for your views. Instead of views
3aad2f3 @defunkt docs
defunkt authored
15 consisting of ERB or HAML with random helpers and arbitrary logic,
16 your views are broken into two parts: a Ruby class and an HTML
17 template.
18
19 We call the Ruby class the "view" and the HTML template the
20 "template."
21
22 All your logic, decisions, and code is contained in your view. All
23 your markup is contained in your template. The template does nothing
d5258f3 @defunkt whitespace
defunkt authored
24 but reference methods in your view.
3aad2f3 @defunkt docs
defunkt authored
25
26 This strict separation makes it easier to write clean templates,
27 easier to test your views, and more fun to work on your app's front end.
28
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
29
1d6dfee @defunkt why?
defunkt authored
30 Why?
31 ----
32
33 I like writing Ruby. I like writing HTML. I like writing JavaScript.
34
35 I don't like writing ERB, Haml, Liquid, Django Templates, putting Ruby
36 in my HTML, or putting JavaScript in my HTML.
37
38
3aad2f3 @defunkt docs
defunkt authored
39 Usage
40 -----
41
debca50 Quick example.
Francesc Esplugas authored
42 Quick example:
43
44 >> require 'mustache'
45 => true
46 >> Mustache.render("Hello {{planet}}", :planet => "World!")
47 => "Hello World!"
48
3aad2f3 @defunkt docs
defunkt authored
49 We've got an `examples` folder but here's the canonical one:
50
f0857e5 @defunkt rtemplate => mustache
defunkt authored
51 class Simple < Mustache
3aad2f3 @defunkt docs
defunkt authored
52 def name
53 "Chris"
54 end
55
56 def value
57 10_000
58 end
59
60 def taxed_value
61 value - (value * 0.4)
62 end
63
64 def in_ca
65 true
66 end
67 end
68
69 We simply create a normal Ruby class and define methods. Some methods
70 reference others, some return values, some return only booleans.
71
72 Now let's write the template:
73
74 Hello {{name}}
75 You have just won ${{value}}!
76 {{#in_ca}}
77 Well, ${{taxed_value}}, after taxes.
78 {{/in_ca}}
79
80 This template references our view methods. To bring it all together,
81 here's the code to render actual HTML;
82
9b245dd @defunkt `render` is the new `to_html`
defunkt authored
83 Simple.render
3aad2f3 @defunkt docs
defunkt authored
84
85 Which returns the following:
86
87 Hello Chris
88 You have just won $10000!
89 Well, $6000.0, after taxes.
90
91 Simple.
92
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
93
94 Tag Types
95 ---------
96
97 Tags are indicated by the double mustaches. `{{name}}` is a tag. Let's
98 talk about the different types of tags.
99
100 ### Variables
101
102 The most basic tag is the variable. A `{{name}}` tag in a basic
103 template will try to call the `name` method on your view. If there is
104 no `name` method, an exception will be raised.
105
6f73fdf @defunkt Add a note in the README about raise_on_context_miss
defunkt authored
106 All variables are HTML escaped by default. If you want to return
107 unescaped HTML, use the triple mustache: `{{{name}}}`.
108
109 By default a variable "miss" returns an empty string. You can
110 configure this by setting `Mustache.raise_on_context_miss` to true.
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
111
112 ### Boolean Sections
113
114 A section begins with a pound and ends with a slash. That is,
115 `{{#person}}` begins a "person" section while `{{/person}}` ends it.
116
117 If the `person` method exists and calling it returns false, the HTML
118 between the pound and slash will not be displayed.
119
120 If the `person` method exists and calling it returns true, the HTML
121 between the pound and slash will be rendered and displayed.
122
123 ### Enumerable Sections
124
125 Enumerable sections are syntactically identical to boolean sections in
126 that they begin with a pound and end with a slash. The difference,
127 however, is in the view: if the method called returns an enumerable,
d5258f3 @defunkt whitespace
defunkt authored
128 the section is repeated as the enumerable is iterated over.
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
129
130 Each item in the enumerable is expected to be a hash which will then
131 become the context of the corresponding iteration. In this way we can
132 construct loops.
133
134 For example, imagine this template:
135
136 {{#repo}}
137 <b>{{name}}</b>
138 {{/repo}}
139
140 And this view code:
141
142 def repo
143 Repository.all.map { |r| { :name => r.to_s } }
144 end
145
146 When rendered, our view will contain a list of all repository names in
147 the database.
148
4f19541 @defunkt document hash shortcut
defunkt authored
149 As a convenience, if a section returns a hash (as opposed to an array
150 or a boolean) it will be treated as a single item array.
151
152 With the above template, we could use this Ruby code for a single
153 iteration:
154
155 def repo
156 { :name => Repository.first.to_s }
157 end
158
159 This would be treated by Mustache as functionally equivalent to the
160 following:
161
162 def repo
163 [ { :name => Repository.first.to_s } ]
164 end
165
166
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
167 ### Comments
168
169 Comments begin with a bang and are ignored. The following template:
170
171 <h1>Today{{! ignore me }}.</h1>
d5258f3 @defunkt whitespace
defunkt authored
172
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
173 Will render as follows:
174
175 <h1>Today.</h1>
176
177 ### Partials
178
bc104d1 @defunkt ctemplate compat: Partials are indicated by >, not <
defunkt authored
179 Partials begin with a greater than sign, like `{{> box}}`.
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
180
181 If a partial's view is loaded, we use that to render the HTML. If
182 nothing is loaded we render the template directly using our current context.
183
184 In this way partials can reference variables or sections the calling
185 view defines.
186
187
3e42d49 @defunkt document Set Delimiter
defunkt authored
188 ### Set Delimiter
189
190 Set Delimiter tags start with an equal sign and change the tag
191 delimiters from {{ and }} to custom strings.
192
193 Consider the following contrived example:
194
195 * {{ default_tags }}
196 {{=<% %>=}}
197 * <% erb_style_tags %>
198 <%={{ }}=%>
199 * {{ default_tags_again }}
200
201 Here we have a list with three items. The first item uses the default
202 tag style, the second uses erb style as defined by the Set Delimiter
203 tag, and the third returns to the default style after yet another Set
204 Delimiter declaration.
205
206 According to [ctemplates][3], this "is useful for languages like TeX, where
207 double-braces may occur in the text and are awkward to use for
208 markup."
209
210 Custom delimiters may not contain whitespace or the equals sign.
211
212
04e852b @defunkt explain the dict style
defunkt authored
213 Dict-Style Views
214 ----------------
215
216 ctemplate and friends want you to hand a dictionary to the template
515de91 @defunkt Dict example uses Winner to be more explicit, less confusing
defunkt authored
217 processor. Mustache supports a similar concept. Feel free to mix the
218 class-based and this more procedural style at your leisure.
04e852b @defunkt explain the dict style
defunkt authored
219
07144e4 @defunkt Update readme with .html => .mustache change
defunkt authored
220 Given this template (winner.mustache):
04e852b @defunkt explain the dict style
defunkt authored
221
222 Hello {{name}}
223 You have just won ${{value}}!
224
225 We can fill in the values at will:
d5258f3 @defunkt whitespace
defunkt authored
226
515de91 @defunkt Dict example uses Winner to be more explicit, less confusing
defunkt authored
227 view = Winner.new
228 view[:name] = 'George'
229 view[:value] = 100
230 view.render
04e852b @defunkt explain the dict style
defunkt authored
231
232 Which returns:
d5258f3 @defunkt whitespace
defunkt authored
233
04e852b @defunkt explain the dict style
defunkt authored
234 Hello George
235 You have just won $100!
236
237 We can re-use the same object, too:
238
515de91 @defunkt Dict example uses Winner to be more explicit, less confusing
defunkt authored
239 view[:name] = 'Tony'
240 view.render
04e852b @defunkt explain the dict style
defunkt authored
241 Hello Tony
242 You have just won $100!
243
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
244
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
245 Templates
246 ---------
247
248 A word on templates. By default, a view will try to find its template
249 on disk by searching for an HTML file in the current directory that
250 follows the classic Ruby naming convention.
251
07144e4 @defunkt Update readme with .html => .mustache change
defunkt authored
252 TemplatePartial => ./template_partial.mustache
d5258f3 @defunkt whitespace
defunkt authored
253
3291a2d @defunkt document template_extension in the README
defunkt authored
254 You can set the search path using `Mustache.template_path`. It can be set on a
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
255 class by class basis:
256
f0857e5 @defunkt rtemplate => mustache
defunkt authored
257 class Simple < Mustache
3291a2d @defunkt document template_extension in the README
defunkt authored
258 self.template_path = File.dirname(__FILE__)
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
259 ... etc ...
260 end
261
07144e4 @defunkt Update readme with .html => .mustache change
defunkt authored
262 Now `Simple` will look for `simple.mustache` in the directory it resides
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
263 in, no matter the cwd.
264
265 If you want to just change what template is used you can set
5b3b4c3 @judofyr Compile into a Proc (for speed). This required more changes:
judofyr authored
266 `Mustache.template_file` directly:
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
267
07144e4 @defunkt Update readme with .html => .mustache change
defunkt authored
268 Simple.template_file = './blah.mustache'
d5258f3 @defunkt whitespace
defunkt authored
269
3291a2d @defunkt document template_extension in the README
defunkt authored
270 Mustache also allows you to define the extension it'll use.
271
272 Simple.template_extension = 'xml'
273
274 Given all other defaults, the above line will cause Mustache to look
275 for './blah.xml'
276
277 Feel free to set the template directly:
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
278
5b3b4c3 @judofyr Compile into a Proc (for speed). This required more changes:
judofyr authored
279 Simple.template = 'Hi {{person}}!'
280
3291a2d @defunkt document template_extension in the README
defunkt authored
281 Or set a different template for a single instance:
5b3b4c3 @judofyr Compile into a Proc (for speed). This required more changes:
judofyr authored
282
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
283 Simple.new.template = 'Hi {{person}}!'
284
285 Whatever works.
286
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
287
40313b9 @defunkt Added autoloading
defunkt authored
288 Views
289 -----
290
291 Mustache supports a bit of magic when it comes to views. If you're
292 authoring a plugin or extension for a web framework (Sinatra, Rails,
293 etc), check out the `view_namespace` and `view_path` settings on the
294 `Mustache` class. They will surely provide needed assistance.
295
296
70af848 @defunkt helpers?!
defunkt authored
297 Helpers
298 -------
299
300 What about global helpers? Maybe you have a nifty `gravatar` function
d5258f3 @defunkt whitespace
defunkt authored
301 you want to use in all your views? No problem.
70af848 @defunkt helpers?!
defunkt authored
302
303 This is just Ruby, after all.
304
305 module ViewHelpers
306 def gravatar(email, size = 30)
307 gravatar_id = Digest::MD5.hexdigest(email.to_s.strip.downcase)
308 gravatar_for_id(gravatar_id, size)
309 end
310
311 def gravatar_for_id(gid, size = 30)
312 "#{gravatar_host}/avatar/#{gid}?s=#{size}"
313 end
314
315 def gravatar_host
316 @ssl ? 'https://secure.gravatar.com' : 'http://www.gravatar.com'
317 end
318 end
319
d5258f3 @defunkt whitespace
defunkt authored
320 Then just include it:
70af848 @defunkt helpers?!
defunkt authored
321
f0857e5 @defunkt rtemplate => mustache
defunkt authored
322 class Simple < Mustache
70af848 @defunkt helpers?!
defunkt authored
323 include ViewHelpers
324
325 def name
326 "Chris"
327 end
328
329 def value
330 10_000
331 end
332
333 def taxed_value
334 value - (value * 0.4)
335 end
336
337 def in_ca
338 true
339 end
340 end
341
342 Great, but what about that `@ssl` ivar in `gravatar_host`? There are
343 many ways we can go about setting it.
344
f0857e5 @defunkt rtemplate => mustache
defunkt authored
345 Here's on example which illustrates a key feature of Mustache: you
70af848 @defunkt helpers?!
defunkt authored
346 are free to use the `initialize` method just as you would in any
347 normal class.
348
f0857e5 @defunkt rtemplate => mustache
defunkt authored
349 class Simple < Mustache
70af848 @defunkt helpers?!
defunkt authored
350 include ViewHelpers
351
352 def initialize(ssl = false)
353 @ssl = ssl
354 end
355
356 ... etc ...
357 end
358
359 Now:
360
9b245dd @defunkt `render` is the new `to_html`
defunkt authored
361 Simple.new(request.ssl?).render
70af848 @defunkt helpers?!
defunkt authored
362
363 Convoluted but you get the idea.
364
365
d7d6f66 @defunkt mention sinatra integration in README
defunkt authored
366 Sinatra
367 -------
368
369 Mustache ships with Sinatra integration. Please see
370 `lib/mustache/sinatra.rb` or
371 <http://defunkt.github.com/mustache/classes/Mustache/Sinatra.html> for
372 complete documentation.
373
ca40124 @defunkt reference the mustache-sinatra-example
defunkt authored
374 An example Sinatra application is also provided:
375 <http://github.com/defunkt/mustache-sinatra-example>
376
d7d6f66 @defunkt mention sinatra integration in README
defunkt authored
377
50ec6b7 @defunkt Added Rack::Bug panel
defunkt authored
378 [Rack::Bug][4]
379 ---------
380
381 Mustache also ships with a `Rack::Bug` panel. In your `config.ru` add
382 the following code:
383
384 require 'rack/bug/panels/mustache_panel'
385 use Rack::Bug::MustachePanel
386
387 Using Rails? Add this to your initializer or environment file:
388
389 require 'rack/bug/panels/mustache_panel'
390 config.middleware.use "Rack::Bug::MustachePanel"
391
e5ae462 @defunkt screenshot!
defunkt authored
392 [![Rack::Bug](http://img.skitch.com/20091027-xyf4h1yxnefpp7usyddrcmc7dn.png)][5]
393
50ec6b7 @defunkt Added Rack::Bug panel
defunkt authored
394
da44c7e @defunkt Add mustache.vim [Juvenn Woo]
defunkt authored
395 Vim
396 ---
397
398 Thanks to [Juvenn Woo](http://github.com/juvenn) for mustache.vim. It
399 is included under the contrib/ directory.
400
401
13bd8ed @defunkt Added tpl-mode.el to contrib/ for us Emacs users
defunkt authored
402 Emacs
6f04090 @defunkt Mention Tekkub's Mustache TextMate bundle
defunkt authored
403 -----
13bd8ed @defunkt Added tpl-mode.el to contrib/ for us Emacs users
defunkt authored
404
405 tpl-mode.el is included under the contrib/ directory for any Emacs users.
406 Based on Google's tpl-mode for ctemplates, it adds support for Mustache's
407 more lenient tag values and includes a few commands for your editing pleasure.
408
409
6f04090 @defunkt Mention Tekkub's Mustache TextMate bundle
defunkt authored
410 TextMate
411 --------
412
413 Check out Tekkub's
414 [Mustache.tmbundle](http://github.com/tekkub/Mustache.tmbundle).
415
416
b6e396f @defunkt add installation and docs
defunkt authored
417 Installation
418 ------------
419
420 ### [Gemcutter](http://gemcutter.org/)
421
422 $ gem install mustache
d5258f3 @defunkt whitespace
defunkt authored
423
b6e396f @defunkt add installation and docs
defunkt authored
424 ### [Rip](http://hellorip.com)
425
426 $ rip install git://github.com/defunkt/mustache.git
427
428
05bedeb @defunkt acknowledgements
defunkt authored
429 Acknowledgements
430 ----------------
431
432 Thanks to [Tom Preston-Werner](http://github.com/mojombo) for showing
433 me ctemplate and [Leah Culver](http://github.com/leah) for the name "Mustache."
434
435
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
436 Meta
437 ----
141fa9a @defunkt partials docs
defunkt authored
438
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
439 * Code: `git clone git://github.com/defunkt/mustache.git`
a289c2b @defunkt add Home link
defunkt authored
440 * Home: <http://github.com/defunkt/mustache>
b6e396f @defunkt add installation and docs
defunkt authored
441 * Docs: <http://defunkt.github.com/mustache>
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
442 * Bugs: <http://github.com/defunkt/mustache/issues>
443 * List: <http://groups.google.com/group/mustache-rb>
ff3cb6d @defunkt add runcoderun link
defunkt authored
444 * Test: <http://runcoderun.com/defunkt/mustache>
48b933c @defunkt add Gems link
defunkt authored
445 * Gems: <http://gemcutter.org/gems/mustache>
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
446 * Boss: Chris Wanstrath :: <http://github.com/defunkt>
02edd2c @defunkt references make the first paragraph it read easier
defunkt authored
447
448 [1]: http://code.google.com/p/google-ctemplate/
449 [2]: http://www.ivan.fomichev.name/2008/05/erlang-template-engine-prototype.html
3e42d49 @defunkt document Set Delimiter
defunkt authored
450 [3]: http://google-ctemplate.googlecode.com/svn/trunk/doc/howto.html
50ec6b7 @defunkt Added Rack::Bug panel
defunkt authored
451 [4]: http://github.com/brynary/rack-bug/
e5ae462 @defunkt screenshot!
defunkt authored
452 [5]: http://img.skitch.com/20091027-n8pxwwx8r61tc318a15q1n6m14.png
Something went wrong with that request. Please try again.