mustache 0.99.4 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +183 -183
  3. data/Rakefile +6 -14
  4. data/bin/mustache +28 -14
  5. data/lib/mustache/context.rb +98 -46
  6. data/lib/mustache/context_miss.rb +55 -0
  7. data/lib/mustache/enumerable.rb +3 -0
  8. data/lib/mustache/generator.rb +63 -42
  9. data/lib/mustache/parser.rb +173 -65
  10. data/lib/mustache/settings.rb +84 -24
  11. data/lib/mustache/template.rb +74 -4
  12. data/lib/mustache/utils.rb +31 -0
  13. data/lib/mustache/version.rb +1 -1
  14. data/lib/mustache.rb +116 -96
  15. data/man/mustache.1 +25 -40
  16. data/man/mustache.1.html +90 -81
  17. data/man/mustache.1.ron +6 -6
  18. data/man/mustache.5 +338 -298
  19. data/man/mustache.5.html +400 -115
  20. data/man/mustache.5.ron +292 -32
  21. data/test/autoloading_test.rb +7 -3
  22. data/test/fixtures/comments.rb +0 -1
  23. data/test/fixtures/complex_view.rb +0 -1
  24. data/test/fixtures/crazy_recursive.rb +0 -1
  25. data/test/fixtures/delimiters.rb +0 -1
  26. data/test/fixtures/dot_notation.rb +0 -1
  27. data/test/fixtures/double_section.rb +0 -1
  28. data/test/fixtures/inverted_section.rb +0 -1
  29. data/test/fixtures/lambda.rb +0 -1
  30. data/test/fixtures/liberal.mustache +1 -0
  31. data/test/fixtures/liberal.rb +25 -0
  32. data/test/fixtures/method_missing.rb +0 -1
  33. data/test/fixtures/namespaced.rb +0 -1
  34. data/test/fixtures/nested_objects.rb +0 -1
  35. data/test/fixtures/override/passenger.conf +6 -0
  36. data/test/fixtures/partial_with_module.rb +0 -1
  37. data/test/fixtures/passenger.rb +0 -1
  38. data/test/fixtures/recursive.rb +0 -1
  39. data/test/fixtures/simple.rb +0 -1
  40. data/test/fixtures/simply_complicated.mustache +25 -0
  41. data/test/fixtures/template_partial.rb +0 -1
  42. data/test/fixtures/unescaped.rb +0 -1
  43. data/test/helper.rb +5 -2
  44. data/test/mustache_test.rb +210 -25
  45. data/test/parser_test.rb +90 -7
  46. data/test/partial_test.rb +16 -4
  47. data/test/path_test.rb +49 -0
  48. data/test/spec_test.rb +5 -5
  49. data/test/template_test.rb +35 -3
  50. metadata +37 -59
  51. data/lib/mustache/sinatra.rb +0 -186
  52. data/lib/rack/bug/panels/mustache_panel/mustache_extension.rb +0 -27
  53. data/lib/rack/bug/panels/mustache_panel/view.mustache +0 -46
  54. data/lib/rack/bug/panels/mustache_panel.rb +0 -81
data/man/mustache.5.ron CHANGED
@@ -38,6 +38,12 @@ clauses, or for loops. Instead there are only tags. Some tags are
38
38
  replaced with a value, some nothing, and others a series of
39
39
  values. This document explains the different types of Mustache tags.
40
40
 
41
+ The Mustache language has a [formal specification][spec]. The current
42
+ manpage reflects version 1.3.0 of the specification, including the
43
+ official-but-optional extensions for lambdas and inheritance.
44
+
45
+ [spec]: https://github.com/mustache/spec
46
+
41
47
 
42
48
  ## TAG TYPES
43
49
 
@@ -50,12 +56,14 @@ or tag key. Let's talk about the different types of tags.
50
56
 
51
57
  The most basic tag type is the variable. A `{{name}}` tag in a basic
52
58
  template will try to find the `name` key in the current context. If
53
- there is no `name` key, nothing will be rendered.
59
+ there is no `name` key, the parent contexts will be checked recursively.
60
+ If the top context is reached and the `name` key is still not found,
61
+ nothing will be rendered.
54
62
 
55
- All variables are HTML escaped by default. If you want to return
56
- unescaped HTML, use the triple mustache: `{{{name}}}`.
63
+ All variables are HTML escaped by default. If you want to return raw contents
64
+ without escaping, use the triple mustache: `{{{name}}}`.
57
65
 
58
- You can also use `&` to unescape a variable: `{{& name}}`. This may be
66
+ You can also use `&` to return its raw contents: `{{& name}}`. This may be
59
67
  useful when changing delimiters (see "Set Delimiter" below).
60
68
 
61
69
  By default a variable "miss" returns an empty string. This can usually
@@ -83,16 +91,113 @@ Output:
83
91
  * <b>GitHub</b>
84
92
  * <b>GitHub</b>
85
93
 
94
+ **Dotted Names**
95
+
96
+ If the `name` contains dots, it is split on the dots to obtain multiple
97
+ keys. The first key is looked up in the context as described above. If it
98
+ is found, the next key is looked up within the previous result. This is
99
+ repeated until a key is not found or until the last key is found. The
100
+ final result is interpolated as above.
101
+
102
+ Template:
103
+
104
+ * {{client.name}}
105
+ * {{age}}
106
+ * {{client.company.name}}
107
+ * {{{company.name}}}
108
+
109
+ Hash:
110
+
111
+ {
112
+ "client": {
113
+ "name": "Chris & Friends",
114
+ "age": 50
115
+ },
116
+ "company": {
117
+ "name": "<b>GitHub</b>"
118
+ }
119
+ }
120
+
121
+ Output:
122
+
123
+ * Chris &amp; Friends
124
+ *
125
+ *
126
+ * <b>GitHub</b>
127
+
128
+ **Implicit Iterator**
129
+
130
+ As a special case, if the `name` consists of only a dot and nothing else,
131
+ the value that is the current context is interpolated as a whole. This
132
+ is especially useful if the parent context is a list; see **Sections**
133
+ below.
134
+
135
+ Template:
136
+
137
+ * {{.}}
138
+
139
+ Current context:
140
+
141
+ "Hello!"
142
+
143
+ Output:
144
+
145
+ * Hello!
146
+
147
+ **Lambdas**
148
+
149
+ If any value found during the lookup is a callable object, such as a
150
+ function or lambda, this object will be invoked with zero arguments. The
151
+ value that is returned is then used instead of the callable object itself.
152
+
153
+ An **optional** part of the specification states that if the final key in
154
+ the `name` is a lambda that returns a string, then that string should be
155
+ rendered as a Mustache template before interpolation. It will be rendered
156
+ using the default delimiters (see **Set Delimiter** below) against the
157
+ current context.
158
+
159
+ Template:
160
+
161
+ * {{time.hour}}
162
+ * {{today}}
163
+
164
+ Hash:
165
+
166
+ {
167
+ "year": 1970,
168
+ "month": 1,
169
+ "day": 1,
170
+ "time": function() {
171
+ return {
172
+ "hour": 0,
173
+ "minute": 0,
174
+ "second": 0
175
+ }
176
+ },
177
+ "today": function() {
178
+ return "{{year}}-{{month}}-{{day}}"
179
+ }
180
+ }
181
+
182
+ Output:
183
+
184
+ * 0
185
+ * 1970-1-1
186
+
86
187
 
87
188
  ### Sections
88
189
 
89
- Sections render blocks of text one or more times, depending on the
190
+ Sections render blocks of text zero or more times, depending on the
90
191
  value of the key in the current context.
91
192
 
193
+ Lookup of dotted names works in the same way as with variables, except for
194
+ slightly different treatment of lambdas. More on this below.
195
+
92
196
  A section begins with a pound and ends with a slash. That is,
93
197
  `{{#person}}` begins a "person" section while `{{/person}}` ends it.
94
198
 
95
- The behavior of the section is determined by the value of the key.
199
+ The behavior of the section is determined by the final value of the key
200
+ lookup.
96
201
 
97
202
  **False Values or Empty Lists**
98
203
 
@@ -102,14 +207,14 @@ list, the HTML between the pound and slash will not be displayed.
102
207
  Template:
103
208
 
104
209
  Shown.
105
- {{#nothin}}
210
+ {{#person}}
106
211
  Never shown!
107
- {{/nothin}}
212
+ {{/person}}
108
213
 
109
214
  Hash:
110
215
 
111
216
  {
112
- "person": true,
217
+ "person": false
113
218
  }
114
219
 
115
220
  Output:
@@ -118,7 +223,7 @@ Output:
118
223
 
119
224
  **Non-Empty Lists**
120
225
 
121
- If the `person` key exists and has a non-false value, the HTML between
226
+ If the `repo` key exists and has a non-false value, the HTML between
122
227
  the pound and slash will be rendered and displayed one or more times.
123
228
 
124
229
  When the value is a non-empty list, the text in the block will be
@@ -138,38 +243,60 @@ Hash:
138
243
  "repo": [
139
244
  { "name": "resque" },
140
245
  { "name": "hub" },
141
- { "name": "rip" },
246
+ { "name": "rip" }
142
247
  ]
143
248
  }
144
249
 
145
250
  Output:
146
251
 
147
- <b>resque</b>
148
- <b>hub</b>
149
- <b>rip</b>
252
+ <b>resque</b>
253
+ <b>hub</b>
254
+ <b>rip</b>
255
+
256
+ The same effect as above can be obtained without nested objects, by using
257
+ the implicit iterator (see **Variables** above).
258
+
259
+ Template:
260
+
261
+ {{#repo}}
262
+ <b>{{.}}</b>
263
+ {{/repo}}
264
+
265
+ Hash:
266
+
267
+ {
268
+ "repo": ["resque", "hub", "rip"]
269
+ }
270
+
271
+ Output:
272
+
273
+ <b>resque</b>
274
+ <b>hub</b>
275
+ <b>rip</b>
150
276
 
151
277
  **Lambdas**
152
278
 
153
- When the value is a callable object, such as a function or lambda, the
154
- object will be invoked and passed the block of text. The text passed
155
- is the literal block, unrendered. `{{tags}}` will not have been expanded
156
- - the lambda should do that on its own. In this way you can implement
157
- filters or caching.
279
+ When any value found during the lookup is a callable object, such as a
280
+ function or lambda, the object will be invoked and passed the block of
281
+ text. The text passed is the literal block, unrendered. `{{tags}}` will
282
+ not have been expanded.
283
+
284
+ An **optional** part of the specification states that if the final key in
285
+ the `name` is a lambda that returns a string, then that string replaces
286
+ the content of the section. It will be rendered using the same delimiters
287
+ (see **Set Delimiter** below) as the original section content. In this way
288
+ you can implement filters or caching.
158
289
 
159
290
  Template:
160
291
 
161
- {{#wrapped}}
162
- {{name}} is awesome.
163
- {{/wrapped}}
292
+ {{#wrapped}}{{name}} is awesome.{{/wrapped}}
164
293
 
165
294
  Hash:
166
295
 
167
296
  {
168
297
  "name": "Willy",
169
- "wrapped": function() {
170
- return function(text) {
171
- return "<b>" + render(text) + "</b>"
172
- }
298
+ "wrapped": function(text) {
299
+ return "<b>" + text + "</b>"
173
300
  }
174
301
  }
175
302
 
@@ -196,7 +323,7 @@ Hash:
196
323
 
197
324
  Output:
198
325
 
199
- Hi Jon!
326
+ Hi Jon!
200
327
 
201
328
 
202
329
  ### Inverted Sections
@@ -205,7 +332,7 @@ An inverted section begins with a caret (hat) and ends with a
205
332
  slash. That is `{{^person}}` begins a "person" inverted section while
206
333
  `{{/person}}` ends it.
207
334
 
208
- While sections can be used to render text one or more times based on the
335
+ While sections can be used to render text zero or more times based on the
209
336
  value of the key, inverted sections may render text once based
210
337
  on the inverse value of the key. That is, they will be rendered
211
338
  if the key doesn't exist, is false, or is an empty list.
@@ -227,7 +354,7 @@ Hash:
227
354
 
228
355
  Output:
229
356
 
230
- No repos :(
357
+ No repos :(
231
358
 
232
359
 
233
360
  ### Comments
@@ -284,6 +411,139 @@ Can be thought of as a single, expanded template:
284
411
  {{/names}}
285
412
 
286
413
 
414
+ **Dynamic Names**
415
+
416
+ Partials can be loaded dynamically at runtime using Dynamic Names; an
417
+ **optional** part of the Mustache specification which allows to dynamically
418
+ determine a tag's content at runtime.
419
+
420
+ Dynamic Names consists of an asterisk, followed by a dotted name which follows
421
+ the same notation and the same resolution as in an variable tag. That is
422
+ `{{>*dynamic}}`. It can be thought as the following **hypothetical** tag
423
+ (which is **not allowed**!): `{{>{{dynamic}}}}`.
424
+
425
+ Templates:
426
+
427
+ main.mustache:
428
+ Hello {{>*dynamic}}
429
+
430
+ world.template:
431
+ everyone!
432
+
433
+ Hash:
434
+
435
+ {
436
+ "dynamic": "world"
437
+ }
438
+
439
+ Output:
440
+
441
+ Hello everyone!
442
+
443
+
444
+ ### Blocks
445
+
446
+ A block begins with a dollar and ends with a slash. That is, `{{$title}}`
447
+ begins a "title" block and `{{/title}}` ends it.
448
+
449
+ Blocks mark parts of the template that may be overridden. This can be done
450
+ with a block of the same name within a parent section in the calling
451
+ template (see **Parents** below). If not overridden, the contents of a
452
+ block render just as if the `{{$title}}` and `{{/title}}` tags weren't
453
+ there.
454
+
455
+ Blocks could be thought of as template parameters or as inline partials
456
+ that may be passed to another template. They are part of the optional
457
+ inheritance extension.
458
+
459
+ Template `article.mustache`:
460
+
461
+ <h1>{{$title}}The News of Today{{/title}}</h1>
462
+ {{$body}}
463
+ <p>Nothing special happened.</p>
464
+ {{/body}}
465
+
466
+ Output:
467
+
468
+ <h1>The News of Today</h1>
469
+ <p>Nothing special happened.</p>
470
+
471
+
472
+ ### Parents
473
+
474
+ A parent begins with a less than sign and ends with a slash. That is,
475
+ `{{<article}}` begins an "article" parent and `{{/article}}` ends it.
476
+
477
+ Like an `{{>article}}` partial, a parent lets you expand another template
478
+ inside the current one. Unlike a partial, a parent also lets you override
479
+ blocks of the other template.
480
+
481
+ Blocks within a parent can again be overridden by another including
482
+ template. Other content within a parent is ignored, like comments.
483
+
484
+ Template:
485
+
486
+ {{<article}}
487
+ Never shown
488
+ {{$body}}
489
+ {{#headlines}}
490
+ <p>{{.}}</p>
491
+ {{/headlines}}
492
+ {{/body}}
493
+ {{/article}}
494
+
495
+ {{<article}}
496
+ {{$title}}Yesterday{{/title}}
497
+ {{/article}}
498
+
499
+ Hash:
500
+
501
+ {
502
+ "headlines": [
503
+ "A pug's handler grew mustaches.",
504
+ "What an exciting day!"
505
+ ]
506
+ }
507
+
508
+ Output, assuming the `article.mustache` from before:
509
+
510
+ <h1>The News of Today</h1>
511
+ <p>A pug's handler grew mustaches.</p>
512
+ <p>What an exciting day!</p>
513
+
514
+ <h1>Yesterday</h1>
515
+ <p>Nothing special happened.</p>
516
+
517
+ **Dynamic Names**
518
+
519
+ Some mustache implementations may allow the use of Dynamic Names in
520
+ parent tags, similar to dynamic names in partials. Here's an example of
521
+ how Dynamic Names in parent tags work.
522
+
523
+ Templates:
524
+
525
+ {{!normal.mustache}}
526
+ {{$text}}Here goes nothing.{{/text}}
527
+
528
+ {{!bold.mustache}}
529
+ <b>{{$text}}Here also goes nothing but it's bold.{{/text}}</b>
530
+
531
+ {{!dynamic.mustache}}
532
+ {{<*dynamic}}
533
+ {{$text}}Hello World!{{/text}}
534
+ {{/*dynamic}}
535
+
536
+ Hash:
537
+
538
+ {
539
+ "dynamic": "bold"
540
+ }
541
+
542
+ Output:
543
+
544
+ <b>Hello World!</b>
545
+
546
+
287
547
  ### Set Delimiter
288
548
 
289
549
  Set Delimiter tags start with an equal sign and change the tag
@@ -308,7 +568,7 @@ markup."
308
568
 
309
569
  Custom delimiters may not contain whitespace or the equals sign.
310
570
 
311
- [ct]: http://google-ctemplate.googlecode.com/svn/trunk/doc/howto.html
571
+ [ct]: http://goog-ctemplate.sourceforge.net/doc/howto.html
312
572
 
313
573
 
314
574
  ## COPYRIGHT
@@ -320,5 +580,5 @@ Original CTemplate by Google
320
580
 
321
581
  ## SEE ALSO
322
582
 
323
- mustache(1), mustache(7),
324
- <http://mustache.github.com/>
583
+ mustache(1),
584
+ <http://mustache.github.io/>
@@ -1,13 +1,17 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__)
2
- require 'helper'
1
+ require_relative 'helper'
3
2
 
4
3
  module TestViews; end
5
4
 
6
- class AutoloadingTest < Test::Unit::TestCase
5
+ class AutoloadingTest < Minitest::Test
7
6
  def setup
8
7
  Mustache.view_path = File.dirname(__FILE__) + '/fixtures'
9
8
  end
10
9
 
10
+ # Restore `view_namespace` to the default value
11
+ def teardown
12
+ Mustache.view_namespace = Object
13
+ end
14
+
11
15
  def test_autoload
12
16
  klass = Mustache.view_class(:Comments)
13
17
  assert_equal Comments, klass
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class Comments < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class ComplexView < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class CrazyRecursive < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class Delimiters < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class DotNotation < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class DoubleSection < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class InvertedSection < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class Lambda < Mustache
@@ -0,0 +1 @@
1
+ {{first-name}} {{middle_name!}} {{lastName?}} {{street-address}}
@@ -0,0 +1,25 @@
1
+ require 'mustache'
2
+
3
+ class Liberal < Mustache
4
+ self.path = File.dirname(__FILE__)
5
+
6
+ def first_name
7
+ "kevin"
8
+ end
9
+
10
+ def middle_name!
11
+ 'j'
12
+ end
13
+
14
+ def lastName?
15
+ 'sheurs'
16
+ end
17
+
18
+ define_method :'street-address' do
19
+ '123 Somewhere St'
20
+ end
21
+ end
22
+
23
+ if $0 == __FILE__
24
+ puts Liberal.to_html
25
+ end
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class MethodMissing < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  module TestViews
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
  require 'ostruct'
4
3
 
@@ -0,0 +1,6 @@
1
+ <VirtualHost *>
2
+ ServerAdmin override@mustache.com
3
+ ServerName {{server}}
4
+ DocumentRoot {{deploy_to}}
5
+ RailsEnv {{stage}}
6
+ </VirtualHost>
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  module SimpleView
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class Passenger < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class Recursive < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class Simple < Mustache
@@ -0,0 +1,25 @@
1
+ Hi there {{yourname}}. Your home directory is {{HOME}}.
2
+
3
+ {{#friend}}
4
+ Your friend is named {{name}}
5
+ {{#morr}}
6
+ Hey {{word}} {{up}} {{{awesomesauce}}}.
7
+ {{/morr}}
8
+ {{^morr}}
9
+ Booooo. {{hiss}}
10
+ {{/morr}}
11
+ {{notinmorr}}
12
+ {{> partial1}}
13
+ {{/friend}}
14
+ {{^friend}}
15
+ You have no friends, {{person}}. You suck.
16
+ {{/friend}}
17
+
18
+ {{> partial2}}
19
+ {{! comments are awesome }}
20
+
21
+ {{={% %}=}}
22
+
23
+ {%love%}
24
+ {%={{ }}=%}
25
+ {{{triplestash}}}
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class TemplatePartial < Mustache
@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
1
  require 'mustache'
3
2
 
4
3
  class Unescaped < Mustache
data/test/helper.rb CHANGED
@@ -1,6 +1,9 @@
1
- require 'test/unit'
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/test/'
4
+ end
2
5
 
3
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/fixtures'
6
+ require 'minitest/autorun'
4
7
 
5
8
  Dir[File.dirname(__FILE__) + '/fixtures/*.rb'].each do |f|
6
9
  require f