Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 349 lines (230 sloc) 8.193 kb
f0857e5 @defunkt rtemplate => mustache
defunkt authored
1 Mustache
6ee6bcf @defunkt first draft
defunkt authored
2 =========
3
4 Inspired by [ctemplate](http://code.google.com/p/google-ctemplate/)
5 and
6 [et](http://www.ivan.fomichev.name/2008/05/erlang-template-engine-prototype.html),
3b9f134 @defunkt typo
defunkt authored
7 Mustache is a framework-agnostic way to render logic-free views.
6ee6bcf @defunkt first draft
defunkt authored
8
b32c566 @defunkt quote ctemplates
defunkt authored
9 As ctemplates says, "It emphasizes separating logic from presentation:
10 it is impossible to embed application logic in this template language."
3aad2f3 @defunkt docs
defunkt authored
11
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
12
3aad2f3 @defunkt docs
defunkt authored
13 Overview
14 --------
15
f0857e5 @defunkt rtemplate => mustache
defunkt authored
16 Think of Mustache as a replacement for your views. Instead of views
3aad2f3 @defunkt docs
defunkt authored
17 consisting of ERB or HAML with random helpers and arbitrary logic,
18 your views are broken into two parts: a Ruby class and an HTML
19 template.
20
21 We call the Ruby class the "view" and the HTML template the
22 "template."
23
24 All your logic, decisions, and code is contained in your view. All
25 your markup is contained in your template. The template does nothing
d5258f3 @defunkt whitespace
defunkt authored
26 but reference methods in your view.
3aad2f3 @defunkt docs
defunkt authored
27
28 This strict separation makes it easier to write clean templates,
29 easier to test your views, and more fun to work on your app's front end.
30
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
31
1d6dfee @defunkt why?
defunkt authored
32 Why?
33 ----
34
35 I like writing Ruby. I like writing HTML. I like writing JavaScript.
36
37 I don't like writing ERB, Haml, Liquid, Django Templates, putting Ruby
38 in my HTML, or putting JavaScript in my HTML.
39
40
3aad2f3 @defunkt docs
defunkt authored
41 Usage
42 -----
43
debca50 Quick example.
Francesc Esplugas authored
44 Quick example:
45
46 >> require 'mustache'
47 => true
48 >> Mustache.render("Hello {{planet}}", :planet => "World!")
49 => "Hello World!"
50
3aad2f3 @defunkt docs
defunkt authored
51 We've got an `examples` folder but here's the canonical one:
52
f0857e5 @defunkt rtemplate => mustache
defunkt authored
53 class Simple < Mustache
3aad2f3 @defunkt docs
defunkt authored
54 def name
55 "Chris"
56 end
57
58 def value
59 10_000
60 end
61
62 def taxed_value
63 value - (value * 0.4)
64 end
65
66 def in_ca
67 true
68 end
69 end
70
71 We simply create a normal Ruby class and define methods. Some methods
72 reference others, some return values, some return only booleans.
73
74 Now let's write the template:
75
76 Hello {{name}}
77 You have just won ${{value}}!
78 {{#in_ca}}
79 Well, ${{taxed_value}}, after taxes.
80 {{/in_ca}}
81
82 This template references our view methods. To bring it all together,
83 here's the code to render actual HTML;
84
85 Simple.new.to_html
86
87 Which returns the following:
88
89 Hello Chris
90 You have just won $10000!
91 Well, $6000.0, after taxes.
92
93 Simple.
94
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
95
96 Tag Types
97 ---------
98
99 Tags are indicated by the double mustaches. `{{name}}` is a tag. Let's
100 talk about the different types of tags.
101
102 ### Variables
103
104 The most basic tag is the variable. A `{{name}}` tag in a basic
105 template will try to call the `name` method on your view. If there is
106 no `name` method, an exception will be raised.
107
108 All variables are HTML escaped by default. If you want, for some
109 reason, to return unescaped HTML you can use the triple mustache:
d5258f3 @defunkt whitespace
defunkt authored
110 `{{{name}}}`.
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
149 ### Comments
150
151 Comments begin with a bang and are ignored. The following template:
152
153 <h1>Today{{! ignore me }}.</h1>
d5258f3 @defunkt whitespace
defunkt authored
154
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
155 Will render as follows:
156
157 <h1>Today.</h1>
158
159 ### Partials
160
161 Partials begin with a less than sign, like `{{< box}}`.
162
163 If a partial's view is loaded, we use that to render the HTML. If
164 nothing is loaded we render the template directly using our current context.
165
166 In this way partials can reference variables or sections the calling
167 view defines.
168
169
04e852b @defunkt explain the dict style
defunkt authored
170 Dict-Style Views
171 ----------------
172
173 ctemplate and friends want you to hand a dictionary to the template
f0857e5 @defunkt rtemplate => mustache
defunkt authored
174 processor. Naturally Mustache supports a similar concept. Feel free
04e852b @defunkt explain the dict style
defunkt authored
175 to mix the class-based and this more procedural style at your leisure.
176
177 Given this template (dict.html):
178
179 Hello {{name}}
180 You have just won ${{value}}!
181
182 We can fill in the values at will:
d5258f3 @defunkt whitespace
defunkt authored
183
04e852b @defunkt explain the dict style
defunkt authored
184 dict = Dict.new
185 dict[:name] = 'George'
186 dict[:value] = 100
187 dict.to_html
188
189 Which returns:
d5258f3 @defunkt whitespace
defunkt authored
190
04e852b @defunkt explain the dict style
defunkt authored
191 Hello George
192 You have just won $100!
193
194 We can re-use the same object, too:
195
196 dict[:name] = 'Tony'
197 dict.to_html
198 Hello Tony
199 You have just won $100!
200
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
201
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
202 Templates
203 ---------
204
205 A word on templates. By default, a view will try to find its template
206 on disk by searching for an HTML file in the current directory that
207 follows the classic Ruby naming convention.
208
209 TemplatePartial => ./template_partial.html
d5258f3 @defunkt whitespace
defunkt authored
210
f0857e5 @defunkt rtemplate => mustache
defunkt authored
211 You can set the search path using `Mustache.path`. It can be set on a
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
212 class by class basis:
213
f0857e5 @defunkt rtemplate => mustache
defunkt authored
214 class Simple < Mustache
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
215 self.path = File.dirname(__FILE__)
216 ... etc ...
217 end
218
219 Now `Simple` will look for `simple.html` in the directory it resides
220 in, no matter the cwd.
221
222 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
223 `Mustache.template_file` directly:
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
224
5b3b4c3 @judofyr Compile into a Proc (for speed). This required more changes:
judofyr authored
225 Simple.template_file = './blah.html'
d5258f3 @defunkt whitespace
defunkt authored
226
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
227 You can also go ahead and set the template directly:
228
5b3b4c3 @judofyr Compile into a Proc (for speed). This required more changes:
judofyr authored
229 Simple.template = 'Hi {{person}}!'
230
231 You can also set a different template for only a single instance:
232
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
233 Simple.new.template = 'Hi {{person}}!'
234
235 Whatever works.
236
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
237
70af848 @defunkt helpers?!
defunkt authored
238 Helpers
239 -------
240
241 What about global helpers? Maybe you have a nifty `gravatar` function
d5258f3 @defunkt whitespace
defunkt authored
242 you want to use in all your views? No problem.
70af848 @defunkt helpers?!
defunkt authored
243
244 This is just Ruby, after all.
245
246 module ViewHelpers
247 def gravatar(email, size = 30)
248 gravatar_id = Digest::MD5.hexdigest(email.to_s.strip.downcase)
249 gravatar_for_id(gravatar_id, size)
250 end
251
252 def gravatar_for_id(gid, size = 30)
253 "#{gravatar_host}/avatar/#{gid}?s=#{size}"
254 end
255
256 def gravatar_host
257 @ssl ? 'https://secure.gravatar.com' : 'http://www.gravatar.com'
258 end
259 end
260
d5258f3 @defunkt whitespace
defunkt authored
261 Then just include it:
70af848 @defunkt helpers?!
defunkt authored
262
f0857e5 @defunkt rtemplate => mustache
defunkt authored
263 class Simple < Mustache
70af848 @defunkt helpers?!
defunkt authored
264 include ViewHelpers
265
266 def name
267 "Chris"
268 end
269
270 def value
271 10_000
272 end
273
274 def taxed_value
275 value - (value * 0.4)
276 end
277
278 def in_ca
279 true
280 end
281 end
282
283 Great, but what about that `@ssl` ivar in `gravatar_host`? There are
284 many ways we can go about setting it.
285
f0857e5 @defunkt rtemplate => mustache
defunkt authored
286 Here's on example which illustrates a key feature of Mustache: you
70af848 @defunkt helpers?!
defunkt authored
287 are free to use the `initialize` method just as you would in any
288 normal class.
289
f0857e5 @defunkt rtemplate => mustache
defunkt authored
290 class Simple < Mustache
70af848 @defunkt helpers?!
defunkt authored
291 include ViewHelpers
292
293 def initialize(ssl = false)
294 @ssl = ssl
295 end
296
297 ... etc ...
298 end
299
300 Now:
301
302 Simple.new(request.ssl?).to_html
303
304 Convoluted but you get the idea.
305
306
d7d6f66 @defunkt mention sinatra integration in README
defunkt authored
307 Sinatra
308 -------
309
310 Mustache ships with Sinatra integration. Please see
311 `lib/mustache/sinatra.rb` or
312 <http://defunkt.github.com/mustache/classes/Mustache/Sinatra.html> for
313 complete documentation.
314
ca40124 @defunkt reference the mustache-sinatra-example
defunkt authored
315 An example Sinatra application is also provided:
316 <http://github.com/defunkt/mustache-sinatra-example>
317
d7d6f66 @defunkt mention sinatra integration in README
defunkt authored
318
b6e396f @defunkt add installation and docs
defunkt authored
319 Installation
320 ------------
321
322 ### [Gemcutter](http://gemcutter.org/)
323
324 $ gem install mustache
d5258f3 @defunkt whitespace
defunkt authored
325
b6e396f @defunkt add installation and docs
defunkt authored
326 ### [Rip](http://hellorip.com)
327
328 $ rip install git://github.com/defunkt/mustache.git
329
330
05bedeb @defunkt acknowledgements
defunkt authored
331 Acknowledgements
332 ----------------
333
334 Thanks to [Tom Preston-Werner](http://github.com/mojombo) for showing
335 me ctemplate and [Leah Culver](http://github.com/leah) for the name "Mustache."
336
337
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
338 Meta
339 ----
141fa9a @defunkt partials docs
defunkt authored
340
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
341 * Code: `git clone git://github.com/defunkt/mustache.git`
a289c2b @defunkt add Home link
defunkt authored
342 * Home: <http://github.com/defunkt/mustache>
b6e396f @defunkt add installation and docs
defunkt authored
343 * Docs: <http://defunkt.github.com/mustache>
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
344 * Bugs: <http://github.com/defunkt/mustache/issues>
345 * List: <http://groups.google.com/group/mustache-rb>
ff3cb6d @defunkt add runcoderun link
defunkt authored
346 * Test: <http://runcoderun.com/defunkt/mustache>
48b933c @defunkt add Gems link
defunkt authored
347 * Gems: <http://gemcutter.org/gems/mustache>
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
348 * Boss: Chris Wanstrath :: <http://github.com/defunkt>
Something went wrong with that request. Please try again.