-
45 |
46 |
- CLASS Mustache 47 | 48 |
├── deps.rip
├── docs
├── created.rid
├── favicon.ico
├── i
│ ├── arrows.png
│ ├── tree_bg.png
│ └── results_bg.png
├── apple-touch-icon.png
├── index.html
├── js
│ └── main.js
├── css
│ ├── reset.css
│ ├── main.css
│ └── panel.css
├── files
│ ├── lib
│ │ ├── mustache
│ │ │ ├── context_rb.html
│ │ │ ├── version_rb.html
│ │ │ ├── generator_rb.html
│ │ │ ├── parser_rb.html
│ │ │ ├── sinatra_rb.html
│ │ │ └── template_rb.html
│ │ ├── mustache_rb.html
│ │ └── rack
│ │ │ └── bug
│ │ │ └── panels
│ │ │ ├── mustache_panel_rb.html
│ │ │ └── mustache_panel
│ │ │ ├── mustache_extension_rb.html
│ │ │ └── view_mustache.html
│ ├── CONTRIBUTORS.html
│ ├── LICENSE.html
│ ├── HISTORY_md.html
│ └── README_md.html
├── classes
│ ├── Rack.html
│ ├── Rack
│ │ ├── Bug.html
│ │ └── Bug
│ │ │ ├── MustachePanel
│ │ │ └── View.html
│ │ │ └── MustachePanel.html
│ ├── Mustache
│ │ ├── ContextMiss.html
│ │ ├── Sinatra.html
│ │ ├── Parser
│ │ │ └── SyntaxError.html
│ │ ├── Template.html
│ │ └── Sinatra
│ │ │ └── Helpers.html
│ └── Object.html
└── panel
│ ├── tree.js
│ └── index.html
├── json.mustache
├── README.md
├── template.mustache
├── tom.coffee
├── Rakefile
├── burt.css
├── data.rb
├── tom.js
├── data.yml
├── extras
├── highlight.css
├── highlight.js
└── mustache.js
├── index.mustache
├── index.html
├── mustache.1.html
└── mustache.5.html
/deps.rip:
--------------------------------------------------------------------------------
1 | hpricot 0.8.2
2 | mustache 0.11.0
3 |
--------------------------------------------------------------------------------
/docs/created.rid:
--------------------------------------------------------------------------------
1 | Sun, 11 Apr 2010 14:18:30 -0400
2 |
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcherry/mustache.github.com/master/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/i/arrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcherry/mustache.github.com/master/docs/i/arrows.png
--------------------------------------------------------------------------------
/docs/i/tree_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcherry/mustache.github.com/master/docs/i/tree_bg.png
--------------------------------------------------------------------------------
/docs/i/results_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcherry/mustache.github.com/master/docs/i/results_bg.png
--------------------------------------------------------------------------------
/docs/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcherry/mustache.github.com/master/docs/apple-touch-icon.png
--------------------------------------------------------------------------------
/json.mustache:
--------------------------------------------------------------------------------
1 | {
2 | "header": "Colors",
3 | "items": [
4 | {"name": "red", "first": true, "url": "#Red"},
5 | {"name": "green", "link": true, "url": "#Green"},
6 | {"name": "blue", "link": true, "url": "#Blue"}
7 | ],
8 | "empty": false
9 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | I am
The list is empty.
17 | {{/empty}} 18 | |={{ }}=| -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 |39 | A ContextMiss is raised whenever a 40 | tag’s target can not be found in the current context if `Mustache#raise_on_context_miss?` is set 42 | to true. 43 |
44 |45 | For example, if your View class does not respond to `music` but your 46 | template contains a `{{music}}` tag this exception will be raised. 47 |
48 |49 | By default it is not raised. See Mustache.raise_on_context_miss. 51 |
52 | 53 |31 | Copyright © 2009 Chris Wanstrath 32 |
33 |34 | Permission is hereby granted, free of charge, to any person obtaining a 35 | copy of this software and associated documentation files (the 36 | “Software”), to deal in the Software without restriction, 37 | including without limitation the rights to use, copy, modify, merge, 38 | publish, distribute, sublicense, and/or sell copies of the Software, and to 39 | permit persons to whom the Software is furnished to do so, subject to the 40 | following conditions: 41 |
42 |43 | The above copyright notice and this permission notice shall be included in 44 | all copies or substantial portions of the Software. 45 |
46 |47 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 48 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 49 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 50 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 51 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 52 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 53 | USE OR OTHER DEALINGS IN THE SOFTWARE. 54 |
55 | 56 || 57 | 58 | |
31 | 46 |
47 |48 |
51 |
70 |
73 |
Logic-less templates.
46 | 47 |48 | Available in 49 | Ruby, 50 | {{#languages}} 51 | {{name}}, 52 | {{/languages}} 53 | {{#last_language}} 54 | and for 55 | {{name}}. 56 | {{/last_language}} 57 |
58 | 59 |60 | Works great with 61 | TextMate, 62 | Vim, 63 | Emacs, 64 | and 65 | Coda. 66 |
67 | 68 |69 | The Manual: 70 | mustache(5) 71 | and 72 | mustache(1) 73 |
74 | 75 |76 | Demo 77 |
78 | 79 | 91 |33 | Support for Mustache in your Sinatra app. 35 |
36 |
37 | require 'mustache/sinatra'
38 |
39 | class Hurl < Sinatra::Base
40 | register Mustache::Sinatra
41 |
42 | set :mustache, {
43 | # Should be the path to your .mustache template files.
44 | :templates => "path/to/mustache/templates",
45 |
46 | # Should be the path to your .rb Mustache view files.
47 | :views => "path/to/mustache/views",
48 |
49 | # This tells Mustache where to look for the Views module,
50 | # under which your View classes should live. By default it's
51 | # the class of your app - in this case `Hurl`. That is, for an :index
52 | # view Mustache will expect Hurl::Views::Index by default.
53 | # If our Sinatra::Base subclass was instead Hurl::App,
54 | # we'd want to do `set :namespace, Hurl::App`
55 | :namespace => Hurl
56 | }
57 |
58 | get '/stats' do
59 | mustache :stats
60 | end
61 | end
62 |
63 | 64 | As noted above, Mustache will look for 65 | `Hurl::Views::Index` when `mustache :index` is called. 66 |
67 |68 | If no `Views::Stats` class exists Mustache 69 | will render the template file directly. 70 |
71 |72 | You can indeed use layouts with this library. Where you’d normally 73 | <%= yield %> you instead {{{yield}}} - the body of the subview is set to 74 | the `yield` variable and made available to you. 75 |
76 | 77 |131 | Called when you `register Mustache::Sinatra` in your Sinatra app. 133 |
134 | 135 |Logic-less templates.
46 | 47 |48 | Available in 49 | Ruby, 50 | JavaScript, 51 | Python, 52 | Erlang, 53 | PHP, 54 | Perl, 55 | Objective-C, 56 | Java, 57 | .NET, 58 | Android, 59 | C++, 60 | Go, 61 | Lua, 62 | ooc, 63 | ActionScript, 64 | ColdFusion, 65 | Scala, 66 | Clojure, 67 | Fantom, 68 | CoffeeScript, 69 | D, 70 | and for 71 | node.js. 72 |
73 | 74 |75 | Works great with 76 | TextMate, 77 | Vim, 78 | Emacs, 79 | and 80 | Coda. 81 |
82 | 83 |84 | The Manual: 85 | mustache(5) 86 | and 87 | mustache(1) 88 |
89 | 90 |91 | Demo 92 |
93 | 94 | 131 |39 | A SyntaxError is raised when the Parser comes across unclosed tags, sections, 41 | illegal content in tags, or anything of that sort. 42 |
43 | 44 |103 | Source: show 104 | 105 | | on GitHub 106 | 107 |
108 |# File lib/mustache/parser.rb, line 30 110 | def initialize(message, position) 111 | @message = message 112 | @lineno, @column, @line = position 113 | @stripped_line = @line.strip 114 | @stripped_column = @column - (@line.size - @line.lstrip.size) 115 | end116 |
mustache -- Mustache processor
mustache <YAML> <FILE>
71 | mustache --compile <FILE>
72 | mustache --tokens <FILE>
73 |
74 |
75 | Mustache is a logic-less templating system for HTML, config files, 78 | anything.
79 | 80 |The mustache command processes a Mustache template preceded by YAML
81 | frontmatter from standard input and prints one or more documents to
82 | standard output.
YAML frontmatter beings with --- on a single line, followed by YAML,
85 | ending with another --- on a single line, e.g.
---
88 | names: [ {name: chris}, {name: mark}, {name: scott} ]
89 | ---
90 |
91 |
92 | If you are unfamiliar with YAML, it is a superset of JSON. Valid JSON 93 | should work fine.
94 | 95 |After the frontmatter should come any valid Mustache template. See 96 | mustache(5) for an overview of Mustache templates.
97 | 98 |For example:
99 | 100 |{{#names}}
101 | Hi {{name}}!
102 | {{/names}}
103 |
104 |
105 | Now let's combine them.
106 | 107 |$ cat data.yml
108 | ---
109 | names: [ {name: chris}, {name: mark}, {name: scott} ]
110 | ---
111 |
112 | $ cat template.mustache
113 | {{#names}}
114 | Hi {{name}}!
115 | {{/names}}
116 |
117 | $ cat data.yml template.mustache | mustache
118 | Hi chris!
119 | Hi mark!
120 | Hi scott!
121 |
122 |
123 | If you provide multiple YAML documents (as delimited by ---), your
124 | template will be rendered multiple times. Like a mail merge.
For example:
127 | 128 |$ cat data.yml
129 | ---
130 | name: chris
131 | ---
132 | name: mark
133 | ---
134 | name: scott
135 | ---
136 |
137 | $ cat template.mustache
138 | Hi {{name}}!
139 |
140 | $ cat data.yml template.mustache | mustache
141 | Hi chris!
142 | Hi mark!
143 | Hi scott!
144 |
145 |
146 | By default mustache will try to render a Mustache template using the
149 | YAML frontmatter you provide. It can do a few other things, however.
-c, --compilePrint the compiled Ruby version of a given template. This is the 153 | code that is actually used when rendering a template into a 154 | string. Useful for debugging but only if you are familiar with 155 | Mustache's internals.
-t, --tokensPrint the tokenized form of a given Mustache template. This can be 157 | used to understand how Mustache parses a template. The tokens are 158 | handed to a generator which compiles them into a Ruby 159 | string. Syntax errors and confused tags, therefor, can probably be 160 | identified by examining the tokens produced.
If you have RubyGems installed:
167 | 168 |gem install mustache
169 |
170 |
171 | $ mustache data.yml template.mustache
174 | $ cat data.yml | mustache - template.mustache
175 | $ mustache -c template.mustache
176 | $ cat <<data | ruby mustache - template.mustache
177 | ---
178 | name: Bob
179 | age: 30
180 | ---
181 | data
182 |
183 |
184 | Mustache is Copyright (C) 2009 Chris Wanstrath
187 | 188 |Original CTemplate by Google
189 | 190 |mustache(5), mustache(7), gem(1), 193 | http://mustache.github.com/
194 | 195 | 196 |92 | Source: show 93 | 94 | | on GitHub 95 | 96 |
97 |# File lib/rack/bug/panels/mustache_panel/mustache_extension.rb, line 22 99 | def [](name) 100 | return real_get(name) if name == :yield || !@mustache.respond_to?(name) 101 | Rack::Bug::MustachePanel.variables[name] = real_get(name) 102 | end103 |
120 | Source: show 121 | 122 | | on GitHub 123 | 124 |
125 |# File lib/rack/bug/panels/mustache_panel/mustache_extension.rb, line 7 127 | def render(*args, &block) 128 | out = '' 129 | Rack::Bug::MustachePanel.times[self.class.name] = Benchmark.realtime do 130 | out = real_render(*args, &block) 131 | end 132 | out 133 | end134 |
mustache :view, :layout => truepartial so you can call super
45 | when providing a custom partial method.Mustache.compile for compiling a template into Ruby.mustache -c FILE to see a template's compiled Ruby.& as an alias for the triple mustache (unescaped HTML).TypeError is no longer thrown when hashes are not
86 | passed.mustache script.mustache script for rendering templates on the command line.view_namespace setting.Mustache.raise_on_context_miss setting (defaults to false)view_namespace and view_path settings to MustacheMustache.view_class method which autoloads a class using the
140 | new view_namespace and view_path settings. Should be used by
141 | plugin developers.view_class methodcompiled? method for checking if a template
177 | has been compiled.compiled? method.template39 | The view is responsible for rendering our panel. While Rack::Bug takes care of the nav, the content 41 | rendered by View is used for the panel itself. 42 |
43 | 44 |100 | We track the render times of all the Mustache views on this page load. 102 |
103 | 104 |137 | Any variables used in this page load are collected and displayed. 138 |
139 | 140 |147 | Source: show 148 | 149 | | on GitHub 150 | 151 |
152 |# File lib/rack/bug/panels/mustache_panel.rb, line 29 154 | def variables 155 | vars = MustachePanel.variables.sort_by { |key, _| key.to_s } 156 | vars.map do |key, value| 157 | # Arrays can get too huge. Just show the first 10 to give you 158 | # some idea. 159 | if value.is_a?(Array) && value.size > 10 160 | size = value.size 161 | value = value.first(10) 162 | value << "...and #{size - 10} more" 163 | end 164 | 165 | { :key => key, :value => value.inspect } 166 | end 167 | end168 |
mustache -- Logic-less templates.
A typical Mustache template:
71 | 72 |Hello {{name}}
73 | You have just won ${{value}}!
74 | {{#in_ca}}
75 | Well, ${{taxed_value}}, after taxes.
76 | {{/in_ca}}
77 |
78 |
79 | Given the following hash:
80 | 81 |{
82 | "name": "Chris",
83 | "value": 10000,
84 | "taxed_value": 10000 - (10000 * 0.4),
85 | "in_ca": true
86 | }
87 |
88 |
89 | Will produce the following:
90 | 91 |Hello Chris
92 | You have just won $10000!
93 | Well, $6000.0, after taxes.
94 |
95 |
96 | Mustache can be used for HTML, config files, source code - 99 | anything. It works by expanding tags in a template using values 100 | provided in a hash or object.
101 | 102 |We call it "logic-less" because there are no if statements, else 103 | clauses, or for loops. Instead there are only tags. Some tags are 104 | replaced with a value, some nothing, and others a series of 105 | values. This document explains the different types of Mustache tags.
106 | 107 |Tags are indicated by the double mustaches. {{person}} is a tag, as
110 | is {{#person}}. In both examples, we'd refer to person as the key
111 | or tag key. Let's talk about the different types of tags.
The most basic tag type is the variable. A {{name}} tag in a basic
116 | template will try to find the name key in the current context. If
117 | there is no name key, nothing will be rendered.
All variables are HTML escaped by default. If you want to return
120 | unescaped HTML, use the triple mustache: {{{name}}}.
You can also use & to unescape a variable: {{& name}}. This may be
123 | useful when changing delimiters (see "Set Delimiter" below).
By default a variable "miss" returns an empty string. This can usually 126 | be configured in your Mustache library. The Ruby version of Mustache 127 | supports raising an exception in this situation, for instance.
128 | 129 |Template:
130 | 131 |* {{name}}
132 | * {{age}}
133 | * {{company}}
134 | * {{{company}}}
135 |
136 |
137 | Hash:
138 | 139 |{
140 | "name": "Chris",
141 | "company": "<b>GitHub</b>"
142 | }
143 |
144 |
145 | Output:
146 | 147 |* Chris
148 | *
149 | * <b>GitHub</b>
150 | * <b>GitHub</b>
151 |
152 |
153 | Sections render blocks of text one or more times, depending on the 156 | value of the key in the current context.
157 | 158 |A section begins with a pound and ends with a slash. That is,
159 | {{#person}} begins a "person" section while {{/person}} ends it.
The behavior of the section is determined by the value of the key.
162 | 163 |False Values or Empty Lists
164 | 165 |If the person key exists and has a value of false or an empty
166 | list, the HTML between the pound and slash will not be displayed.
Template:
169 | 170 |Shown.
171 | {{#nothin}}
172 | Never shown!
173 | {{/nothin}}
174 |
175 |
176 | Hash:
177 | 178 |{
179 | "person": true,
180 | }
181 |
182 |
183 | Output:
184 | 185 |Shown.
186 |
187 |
188 | Non-Empty Lists
189 | 190 |If the person key exists and has a non-false value, the HTML between
191 | the pound and slash will be rendered and displayed one or more times.
When the value is a non-empty list, the text in the block will be 194 | displayed once for each item in the list. The context of the block 195 | will be set to the current item for each iteration. In this way we can 196 | loop over collections.
197 | 198 |Template:
199 | 200 |{{#repo}}
201 | <b>{{name}}</b>
202 | {{/repo}}
203 |
204 |
205 | Hash:
206 | 207 |{
208 | "repo": [
209 | { "name": "resque" },
210 | { "name": "hub" },
211 | { "name": "rip" },
212 | ]
213 | }
214 |
215 |
216 | Output:
217 | 218 |<b>resque</b>
219 | <b>hub</b>
220 | <b>rip</b>
221 |
222 |
223 | Lambdas
224 | 225 |When the value is a callable object, such as a function or lambda, the
226 | object will be invoked and passed the block of text. The text passed
227 | is the literal block, unrendered. {{tags}} will not have been expanded
228 | - the lambda should do that on its own. In this way you can implement
229 | filters or caching.
Template:
232 | 233 |{{#wrapped}}
234 | {{name}} is awesome.
235 | {{/wrapped}}
236 |
237 |
238 | Hash:
239 | 240 |{
241 | "name": "Willy",
242 | "wrapped": function() {
243 | return function(text) {
244 | return "<b>" + render(text) + "</b>"
245 | }
246 | }
247 | }
248 |
249 |
250 | Output:
251 | 252 |<b>Willy is awesome.</b>
253 |
254 |
255 | Non-False Values
256 | 257 |When the value is non-false but not a list, it will be used as the 258 | context for a single rendering of the block.
259 | 260 |Template:
261 | 262 |{{#person?}}
263 | Hi {{name}}!
264 | {{/person?}}
265 |
266 |
267 | Hash:
268 | 269 |{
270 | "person?": { "name": "Jon" }
271 | }
272 |
273 |
274 | Output:
275 | 276 |Hi Jon!
277 |
278 |
279 | An inverted section begins with a caret (hat) and ends with a
282 | slash. That is {{^person}} begins a "person" inverted section while
283 | {{/person}} ends it.
While sections can be used to render text one or more times based on the 286 | value of the key, inverted sections may render text once based 287 | on the inverse value of the key. That is, they will be rendered 288 | if the key doesn't exist, is false, or is an empty list.
289 | 290 |Template:
291 | 292 |{{#repo}}
293 | <b>{{name}}</b>
294 | {{/repo}}
295 | {{^repo}}
296 | No repos :(
297 | {{/repo}}
298 |
299 |
300 | Hash:
301 | 302 |{
303 | "repo": []
304 | }
305 |
306 |
307 | Output:
308 | 309 |No repos :(
310 |
311 |
312 | Comments begin with a bang and are ignored. The following template:
315 | 316 |<h1>Today{{! ignore me }}.</h1>
317 |
318 |
319 | Will render as follows:
320 | 321 |<h1>Today.</h1>
322 |
323 |
324 | Comments may contain newlines.
325 | 326 |Partials begin with a greater than sign, like {{> box}}.
Partials are rendered at runtime (as opposed to compile time), so 331 | recursive partials are possible. Just avoid infinite loops.
332 | 333 |They also inherit the calling context. Whereas in ERB you may have 334 | this:
335 | 336 |<%= partial :next_more, :start => start, :size => size %>
337 |
338 |
339 | Mustache requires only this:
340 | 341 |{{> next_more}}
342 |
343 |
344 | Why? Because the next_more.mustache file will inherit the size and
345 | start methods from the calling context.
In this way you may want to think of partials as includes, or template 348 | expansion, even though it's not literally true.
349 | 350 |For example, this template and partial:
351 | 352 |base.mustache:
353 | <h2>Names</h2>
354 | {{#names}}
355 | {{> user}}
356 | {{/names}}
357 |
358 | user.mustache:
359 | <strong>{{name}}</strong>
360 |
361 |
362 | Can be thought of as a single, expanded template:
363 | 364 |<h2>Names</h2>
365 | {{#names}}
366 | <strong>{{name}}</strong>
367 | {{/names}}
368 |
369 |
370 | Set Delimiter tags start with an equal sign and change the tag
373 | delimiters from {{ and }} to custom strings.
Consider the following contrived example:
376 | 377 |* {{default_tags}}
378 | {{=<% %>=}}
379 | * <% erb_style_tags %>
380 | <%={{ }}=%>
381 | * {{ default_tags_again }}
382 |
383 |
384 | Here we have a list with three items. The first item uses the default 385 | tag style, the second uses erb style as defined by the Set Delimiter 386 | tag, and the third returns to the default style after yet another Set 387 | Delimiter declaration.
388 | 389 |According to ctemplates, this "is useful for languages like TeX, where 390 | double-braces may occur in the text and are awkward to use for 391 | markup."
392 | 393 |Custom delimiters may not contain whitespace or the equals sign.
394 | 395 |Mustache is Copyright (C) 2009 Chris Wanstrath
398 | 399 |Original CTemplate by Google
400 | 401 |mustache(1), mustache(7), 404 | http://mustache.github.com/
405 | 406 | 407 |39 | A Template represents a Mustache template. It compiles and caches a raw 41 | string template into something usable. 42 |
43 |44 | The idea is this: when handed a Mustache 45 | template, convert it into a Ruby string by transforming Mustache tags into interpolated Ruby. 47 |
48 |49 | You shouldn’t use this class directly, instead: 50 |
51 |52 | >> Mustache.render(template, hash) 53 |
54 | 55 || 123 | [R] 124 | | 125 |source | 126 |127 | |
144 | Expects a Mustache template as a string 145 | along with a template path, which it uses to find partials. 146 |
147 | 148 |182 | Does the dirty work of transforming a Mustache template into an 184 | interpolation-friendly Ruby string. 185 |
186 | 187 |225 | Renders the `@source` Mustache template 226 | using the given `context`, which should be a simple hash keyed with 227 | symbols. 228 |
229 |230 | The first time a template is rendered, this method is overriden and from 231 | then on it is “compiled”. Subsequent calls will skip the 232 | compilation step and run the Ruby version of the template directly. 233 |
234 | 235 |242 | Source: show 243 | 244 | | on GitHub 245 | 246 |
247 |# File lib/mustache/template.rb, line 34 249 | def render(context) 250 | # Compile our Mustache template into a Ruby string 251 | compiled = "def render(ctx) #{compile} end" 252 | 253 | # Here we rewrite ourself with the interpolated Ruby version of 254 | # our Mustache template so subsequent calls are very fast and 255 | # can skip the compilation stage. 256 | instance_eval(compiled, __FILE__, __LINE__ - 1) 257 | 258 | # Call the newly rewritten version of #render 259 | render(context) 260 | end261 |
275 | Alias for compile 276 |
277 | 278 |293 | Returns an array of tokens for a given template. 294 |
295 | 296 |39 | MustachePanel is a Rack::Bug panel which tracks the time spent 41 | rendering Mustache views as well as all 42 | the variables accessed during view rendering. 43 |
44 |45 | It can be used to track down slow partials and ensure you’re only 46 | generating data you need. 47 |
48 |49 | Also, it’s fun. 50 |
51 | 52 |151 | Clear out our page load-specific variables. 152 |
153 | 154 |186 | The view render times for this page load 187 |
188 | 189 |220 | The variables used on this page load 221 |
222 | 223 |256 | The content of our Rack::Bug panel 257 |
258 | 259 |292 | The string used for our tab in Rack::Bug’s navigation bar 293 |
294 | 295 |328 | The name of this Rack::Bug panel 329 |
330 | 331 |Inspired by ctemplate and et, Mustache is a 33 | framework-agnostic way to render logic-free views.
34 | 35 |As ctemplates says, "It emphasizes separating logic from presentation: 36 | it is impossible to embed application logic in this template language."
37 | 38 |For a list of implementations (other than Ruby) and tips, see 39 | http://mustache.github.com/.
40 | 41 |Think of Mustache as a replacement for your views. Instead of views 44 | consisting of ERB or HAML with random helpers and arbitrary logic, 45 | your views are broken into two parts: a Ruby class and an HTML 46 | template.
47 | 48 |We call the Ruby class the "view" and the HTML template the 49 | "template."
50 | 51 |All your logic, decisions, and code is contained in your view. All 52 | your markup is contained in your template. The template does nothing 53 | but reference methods in your view.
54 | 55 |This strict separation makes it easier to write clean templates, 56 | easier to test your views, and more fun to work on your app's front end.
57 | 58 |I like writing Ruby. I like writing HTML. I like writing JavaScript.
61 | 62 |I don't like writing ERB, Haml, Liquid, Django Templates, putting Ruby 63 | in my HTML, or putting JavaScript in my HTML.
64 | 65 |Quick example:
68 | 69 |>> require 'mustache'
70 | => true
71 | >> Mustache.render("Hello {{planet}}", :planet => "World!")
72 | => "Hello World!"
73 |
74 |
75 | We've got an examples folder but here's the canonical one:
class Simple < Mustache
78 | def name
79 | "Chris"
80 | end
81 |
82 | def value
83 | 10_000
84 | end
85 |
86 | def taxed_value
87 | value - (value * 0.4)
88 | end
89 |
90 | def in_ca
91 | true
92 | end
93 | end
94 |
95 |
96 | We simply create a normal Ruby class and define methods. Some methods 97 | reference others, some return values, some return only booleans.
98 | 99 |Now let's write the template:
100 | 101 |Hello {{name}}
102 | You have just won ${{value}}!
103 | {{#in_ca}}
104 | Well, ${{taxed_value}}, after taxes.
105 | {{/in_ca}}
106 |
107 |
108 | This template references our view methods. To bring it all together, 109 | here's the code to render actual HTML;
110 | 111 |Simple.render
112 |
113 |
114 | Which returns the following:
115 | 116 |Hello Chris
117 | You have just won $10000!
118 | Well, $6000.0, after taxes.
119 |
120 |
121 | Simple.
122 | 123 |For a language-agnostic overview of Mustache's template syntax, see
126 | the mustache(5) manpage or
127 | http://mustache.github.com/mustache.5.html.
Mustache does escape all values when using the standard double
132 | Mustache syntax. Characters which will be escaped: & \ " < >. To
133 | disable escaping, simply use tripple mustaches like
134 | {{{unescaped_variable}}}.
Example: Using {{variable}} inside a template for 5 > 2 will
137 | result in 5 > 2, where as the usage of {{{variable}}} will
138 | result in 5 > 2.
ctemplate and friends want you to hand a dictionary to the template 143 | processor. Mustache supports a similar concept. Feel free to mix the 144 | class-based and this more procedural style at your leisure.
145 | 146 |Given this template (winner.mustache):
147 | 148 |Hello {{name}}
149 | You have just won ${{value}}!
150 |
151 |
152 | We can fill in the values at will:
153 | 154 |view = Winner.new
155 | view[:name] = 'George'
156 | view[:value] = 100
157 | view.render
158 |
159 |
160 | Which returns:
161 | 162 |Hello George
163 | You have just won $100!
164 |
165 |
166 | We can re-use the same object, too:
167 | 168 |view[:name] = 'Tony'
169 | view.render
170 | Hello Tony
171 | You have just won $100!
172 |
173 |
174 | A word on templates. By default, a view will try to find its template 177 | on disk by searching for an HTML file in the current directory that 178 | follows the classic Ruby naming convention.
179 | 180 |TemplatePartial => ./template_partial.mustache
181 |
182 |
183 | You can set the search path using Mustache.template_path. It can be set on a
184 | class by class basis:
class Simple < Mustache
187 | self.template_path = File.dirname(__FILE__)
188 | ... etc ...
189 | end
190 |
191 |
192 | Now Simple will look for simple.mustache in the directory it resides
193 | in, no matter the cwd.
If you want to just change what template is used you can set
196 | Mustache.template_file directly:
Simple.template_file = './blah.mustache'
199 |
200 |
201 | Mustache also allows you to define the extension it'll use.
202 | 203 |Simple.template_extension = 'xml'
204 |
205 |
206 | Given all other defaults, the above line will cause Mustache to look 207 | for './blah.xml'
208 | 209 |Feel free to set the template directly:
210 | 211 |Simple.template = 'Hi {{person}}!'
212 |
213 |
214 | Or set a different template for a single instance:
215 | 216 |Simple.new.template = 'Hi {{person}}!'
217 |
218 |
219 | Whatever works.
220 | 221 |Mustache supports a bit of magic when it comes to views. If you're
224 | authoring a plugin or extension for a web framework (Sinatra, Rails,
225 | etc), check out the view_namespace and view_path settings on the
226 | Mustache class. They will surely provide needed assistance.
What about global helpers? Maybe you have a nifty gravatar function
231 | you want to use in all your views? No problem.
This is just Ruby, after all.
234 | 235 |module ViewHelpers
236 | def gravatar(email, size = 30)
237 | gravatar_id = Digest::MD5.hexdigest(email.to_s.strip.downcase)
238 | gravatar_for_id(gravatar_id, size)
239 | end
240 |
241 | def gravatar_for_id(gid, size = 30)
242 | "#{gravatar_host}/avatar/#{gid}?s=#{size}"
243 | end
244 |
245 | def gravatar_host
246 | @ssl ? 'https://secure.gravatar.com' : 'http://www.gravatar.com'
247 | end
248 | end
249 |
250 |
251 | Then just include it:
252 | 253 |class Simple < Mustache
254 | include ViewHelpers
255 |
256 | def name
257 | "Chris"
258 | end
259 |
260 | def value
261 | 10_000
262 | end
263 |
264 | def taxed_value
265 | value - (value * 0.4)
266 | end
267 |
268 | def in_ca
269 | true
270 | end
271 | end
272 |
273 |
274 | Great, but what about that @ssl ivar in gravatar_host? There are
275 | many ways we can go about setting it.
Here's on example which illustrates a key feature of Mustache: you
278 | are free to use the initialize method just as you would in any
279 | normal class.
class Simple < Mustache
282 | include ViewHelpers
283 |
284 | def initialize(ssl = false)
285 | @ssl = ssl
286 | end
287 |
288 | ... etc ...
289 | end
290 |
291 |
292 | Now:
293 | 294 |Simple.new(request.ssl?).render
295 |
296 |
297 | Convoluted but you get the idea.
298 | 299 |Mustache ships with Sinatra integration. Please see
302 | lib/mustache/sinatra.rb or
303 | http://github.com/defunkt/mustache/blob/master/lib/mustache/sinatra.rb
304 | for complete documentation.
An example Sinatra application is also provided: 307 | http://github.com/defunkt/mustache-sinatra-example
308 | 309 |If you are upgrading to Sinatra 1.0 and Mustache 0.9.0+ from Mustache 310 | 0.7.0 or lower, the settings have changed. But not that much.
311 | 312 |See this diff for what you need to
313 | do. Basically, things are named properly now and all should be
314 | contained in a hash set using set :mustache, hash.
Mustache also ships with a Rack::Bug panel. In your config.ru add
319 | the following code:
require 'rack/bug/panels/mustache_panel'
322 | use Rack::Bug::MustachePanel
323 |
324 |
325 | Using Rails? Add this to your initializer or environment file:
326 | 327 |require 'rack/bug/panels/mustache_panel'
328 | config.middleware.use "Rack::Bug::MustachePanel"
329 |
330 |
331 |
332 |
333 | Thanks to Juvenn Woo for mustache.vim. It 336 | is included under the contrib/ directory.
337 | 338 |See http://gist.github.com/323622 for installation instructions.
339 | 340 |mustache-mode.el is included under the contrib/ directory for any 343 | Emacs users. Based on Google's tpl-mode for ctemplates, it adds 344 | support for Mustache's more lenient tag values and includes a few 345 | commands for your editing pleasure.
346 | 347 |See http://gist.github.com/323619 for installation instructions.
348 | 349 |See http://gist.github.com/323624 for installation instructions.
354 | 355 |See mustache(1) man page or
358 | http://mustache.github.com/mustache.1.html
359 | for command line docs.
$ gem install mustache
366 |
367 |
368 | Thanks to Tom Preston-Werner for showing 371 | me ctemplate and Leah Culver for the name "Mustache."
372 | 373 |Special thanks to Magnus Holm for all his 374 | awesome work on Mustache's parser.
375 | 376 |Once you've made your great commits:
379 | 380 |git checkout -b my_branchgit push origin my_branchYou might want to checkout Resque's Contributing wiki page for information 390 | on coding standards, new features, etc.
391 | 392 |To join the list simply send an email to mustache@librelist.com. This 395 | will subscribe you and send you information about your subscription, 396 | including unsubscribe information.
397 | 398 |The archive can be found at http://librelist.com/browser/.
399 | 400 |git clone git://github.com/defunkt/mustache.gitYou can also find us in #{ on irc.freenode.net.
87 | Given a view name and settings, finds and prepares an appropriate view 88 | class for this view. 89 |
90 | 91 |98 | Source: show 99 | 100 | | on GitHub 101 | 102 |
103 |# File lib/mustache/sinatra.rb, line 117 105 | def compile_mustache(view, options = {}) 106 | options[:templates] ||= settings.views if settings.respond_to?(:views) 107 | options[:namespace] ||= self.class 108 | 109 | factory = Class.new(Mustache) do 110 | self.view_namespace = options[:namespace] 111 | self.view_path = options[:views] 112 | end 113 | 114 | # Try to find the view class for a given view, e.g. 115 | # :view => Hurl::Views::Index. 116 | klass = factory.view_class(view) 117 | 118 | # If there is no view class, issue a warning and use the one 119 | # we just generated to cache the compiled template. 120 | if klass == Mustache 121 | warn "No view class found for #{view} in #{factory.view_path}" 122 | klass = factory 123 | 124 | # If this is a generic view class make sure we set the 125 | # template name as it was given. That is, an anonymous 126 | # subclass of Mustache won't know how to find the 127 | # "index.mustache" template unless we tell it to. 128 | klass.template_name = view.to_s 129 | end 130 | 131 | # Set the template path and return our class. 132 | klass.template_path = options[:templates] if options[:templates] 133 | klass 134 | end135 |
149 | Call this in your Sinatra routes. 150 |
151 | 152 |159 | Source: show 160 | 161 | | on GitHub 162 | 163 |
164 |# File lib/mustache/sinatra.rb, line 45 166 | def mustache(template, options={}, locals={}) 167 | # Locals can be passed as options under the :locals key. 168 | locals.update(options.delete(:locals) || {}) 169 | 170 | # Grab any user-defined settings. 171 | if settings.respond_to?(:mustache) 172 | options = settings.send(:mustache).merge(options) 173 | end 174 | 175 | # Find and cache the view class we want. This ensures the 176 | # compiled template is cached, too - no looking up and 177 | # compiling templates on each page load. 178 | klass = mustache_class(template, options) 179 | 180 | # If they aren't explicitly disabling layouts, try to find 181 | # one. 182 | if options[:layout] != false 183 | # Let the user pass in a layout name. 184 | layout_name = options[:layout] 185 | 186 | # If all they said was `true` (or nothing), default to :layout. 187 | layout_name = :layout if layout_name == true || !layout_name 188 | 189 | # If they passed a layout name use that. 190 | layout = mustache_class(layout_name, options) 191 | 192 | # If it's just an anonymous subclass then don't bother, otherwise 193 | # give us a layout instance. 194 | if layout.name && layout.name.empty? 195 | layout = nil 196 | else 197 | layout = layout.new 198 | end 199 | 200 | # Does the view subclass the layout? If so we'll use the 201 | # view to render the layout so you can override layout 202 | # methods in your view - tricky. 203 | view_subclasses_layout = klass < layout.class if layout 204 | end 205 | 206 | # Create a new instance for playing with. 207 | instance = klass.new 208 | 209 | # Copy instance variables set in Sinatra to the view 210 | instance_variables.each do |name| 211 | instance.instance_variable_set(name, instance_variable_get(name)) 212 | end 213 | 214 | # Render with locals. 215 | rendered = instance.render(instance.template, locals) 216 | 217 | # Now render the layout with the view we just rendered, if we 218 | # need to. 219 | if layout && view_subclasses_layout 220 | rendered = instance.render(layout.template, :yield => rendered) 221 | elsif layout 222 | rendered = layout.render(layout.template, :yield => rendered) 223 | end 224 | 225 | # That's it. 226 | rendered 227 | end228 |
242 | Returns a View class for a given template name. 243 |
244 | 245 |