Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 308 lines (204 sloc) 7.208 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
f753a53 @defunkt todo
defunkt authored
9 It's not a markup language because there is no language. There is no
3aad2f3 @defunkt docs
defunkt authored
10 logic.
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
26 but reference methods in your view.
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
44 We've got an `examples` folder but here's the canonical one:
45
f0857e5 @defunkt rtemplate => mustache
defunkt authored
46 class Simple < Mustache
3aad2f3 @defunkt docs
defunkt authored
47 def name
48 "Chris"
49 end
50
51 def value
52 10_000
53 end
54
55 def taxed_value
56 value - (value * 0.4)
57 end
58
59 def in_ca
60 true
61 end
62 end
63
64 We simply create a normal Ruby class and define methods. Some methods
65 reference others, some return values, some return only booleans.
66
67 Now let's write the template:
68
69 Hello {{name}}
70 You have just won ${{value}}!
71 {{#in_ca}}
72 Well, ${{taxed_value}}, after taxes.
73 {{/in_ca}}
74
75 This template references our view methods. To bring it all together,
76 here's the code to render actual HTML;
77
78 Simple.new.to_html
79
80 Which returns the following:
81
82 Hello Chris
83 You have just won $10000!
84 Well, $6000.0, after taxes.
85
86 Simple.
87
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
88
89 Tag Types
90 ---------
91
92 Tags are indicated by the double mustaches. `{{name}}` is a tag. Let's
93 talk about the different types of tags.
94
95 ### Variables
96
97 The most basic tag is the variable. A `{{name}}` tag in a basic
98 template will try to call the `name` method on your view. If there is
99 no `name` method, an exception will be raised.
100
101 All variables are HTML escaped by default. If you want, for some
102 reason, to return unescaped HTML you can use the triple mustache:
103 `{{{name}}}`.
104
105 ### Boolean Sections
106
107 A section begins with a pound and ends with a slash. That is,
108 `{{#person}}` begins a "person" section while `{{/person}}` ends it.
109
110 If the `person` method exists and calling it returns false, the HTML
111 between the pound and slash will not be displayed.
112
113 If the `person` method exists and calling it returns true, the HTML
114 between the pound and slash will be rendered and displayed.
115
116 ### Enumerable Sections
117
118 Enumerable sections are syntactically identical to boolean sections in
119 that they begin with a pound and end with a slash. The difference,
120 however, is in the view: if the method called returns an enumerable,
121 the section is repeated as the enumerable is iterated over.
122
123 Each item in the enumerable is expected to be a hash which will then
124 become the context of the corresponding iteration. In this way we can
125 construct loops.
126
127 For example, imagine this template:
128
129 {{#repo}}
130 <b>{{name}}</b>
131 {{/repo}}
132
133 And this view code:
134
135 def repo
136 Repository.all.map { |r| { :name => r.to_s } }
137 end
138
139 When rendered, our view will contain a list of all repository names in
140 the database.
141
142 ### Comments
143
144 Comments begin with a bang and are ignored. The following template:
145
146 <h1>Today{{! ignore me }}.</h1>
147
148 Will render as follows:
149
150 <h1>Today.</h1>
151
152 ### Partials
153
154 Partials begin with a less than sign, like `{{< box}}`.
155
156 If a partial's view is loaded, we use that to render the HTML. If
157 nothing is loaded we render the template directly using our current context.
158
159 In this way partials can reference variables or sections the calling
160 view defines.
161
162
04e852b @defunkt explain the dict style
defunkt authored
163 Dict-Style Views
164 ----------------
165
166 ctemplate and friends want you to hand a dictionary to the template
f0857e5 @defunkt rtemplate => mustache
defunkt authored
167 processor. Naturally Mustache supports a similar concept. Feel free
04e852b @defunkt explain the dict style
defunkt authored
168 to mix the class-based and this more procedural style at your leisure.
169
170 Given this template (dict.html):
171
172 Hello {{name}}
173 You have just won ${{value}}!
174
175 We can fill in the values at will:
176
177 dict = Dict.new
178 dict[:name] = 'George'
179 dict[:value] = 100
180 dict.to_html
181
182 Which returns:
183
184 Hello George
185 You have just won $100!
186
187 We can re-use the same object, too:
188
189 dict[:name] = 'Tony'
190 dict.to_html
191 Hello Tony
192 You have just won $100!
193
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
194
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
195 Templates
196 ---------
197
198 A word on templates. By default, a view will try to find its template
199 on disk by searching for an HTML file in the current directory that
200 follows the classic Ruby naming convention.
201
202 TemplatePartial => ./template_partial.html
203
f0857e5 @defunkt rtemplate => mustache
defunkt authored
204 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
205 class by class basis:
206
f0857e5 @defunkt rtemplate => mustache
defunkt authored
207 class Simple < Mustache
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
208 self.path = File.dirname(__FILE__)
209 ... etc ...
210 end
211
212 Now `Simple` will look for `simple.html` in the directory it resides
213 in, no matter the cwd.
214
215 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
216 `Mustache.template_file` directly:
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
217
5b3b4c3 @judofyr Compile into a Proc (for speed). This required more changes:
judofyr authored
218 Simple.template_file = './blah.html'
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
219
220 You can also go ahead and set the template directly:
221
5b3b4c3 @judofyr Compile into a Proc (for speed). This required more changes:
judofyr authored
222 Simple.template = 'Hi {{person}}!'
223
224 You can also set a different template for only a single instance:
225
671f6aa @defunkt document template options and make template_file configurable
defunkt authored
226 Simple.new.template = 'Hi {{person}}!'
227
228 Whatever works.
229
0b217cf @defunkt talk about tags first. they're important.
defunkt authored
230
70af848 @defunkt helpers?!
defunkt authored
231 Helpers
232 -------
233
234 What about global helpers? Maybe you have a nifty `gravatar` function
235 you want to use in all your views? No problem.
236
237 This is just Ruby, after all.
238
239 module ViewHelpers
240 def gravatar(email, size = 30)
241 gravatar_id = Digest::MD5.hexdigest(email.to_s.strip.downcase)
242 gravatar_for_id(gravatar_id, size)
243 end
244
245 def gravatar_for_id(gid, size = 30)
246 "#{gravatar_host}/avatar/#{gid}?s=#{size}"
247 end
248
249 def gravatar_host
250 @ssl ? 'https://secure.gravatar.com' : 'http://www.gravatar.com'
251 end
252 end
253
254 Then just include it:
255
f0857e5 @defunkt rtemplate => mustache
defunkt authored
256 class Simple < Mustache
70af848 @defunkt helpers?!
defunkt authored
257 include ViewHelpers
258
259 def name
260 "Chris"
261 end
262
263 def value
264 10_000
265 end
266
267 def taxed_value
268 value - (value * 0.4)
269 end
270
271 def in_ca
272 true
273 end
274 end
275
276 Great, but what about that `@ssl` ivar in `gravatar_host`? There are
277 many ways we can go about setting it.
278
f0857e5 @defunkt rtemplate => mustache
defunkt authored
279 Here's on example which illustrates a key feature of Mustache: you
70af848 @defunkt helpers?!
defunkt authored
280 are free to use the `initialize` method just as you would in any
281 normal class.
282
f0857e5 @defunkt rtemplate => mustache
defunkt authored
283 class Simple < Mustache
70af848 @defunkt helpers?!
defunkt authored
284 include ViewHelpers
285
286 def initialize(ssl = false)
287 @ssl = ssl
288 end
289
290 ... etc ...
291 end
292
293 Now:
294
295 Simple.new(request.ssl?).to_html
296
297 Convoluted but you get the idea.
298
299
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
300 Meta
301 ----
141fa9a @defunkt partials docs
defunkt authored
302
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
303 * Code: `git clone git://github.com/defunkt/mustache.git`
304 * Bugs: <http://github.com/defunkt/mustache/issues>
305 * List: <http://groups.google.com/group/mustache-rb>
ff3cb6d @defunkt add runcoderun link
defunkt authored
306 * Test: <http://runcoderun.com/defunkt/mustache>
190b84d @defunkt project meta info in the readme (issue tracker, mailing list, etc)
defunkt authored
307 * Boss: Chris Wanstrath :: <http://github.com/defunkt>
Something went wrong with that request. Please try again.