mustache 0.99.5 → 0.99.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -44,6 +44,34 @@ EOF
44
44
  end
45
45
  end
46
46
 
47
+ # The sigil types which are valid after an opening `{{`
48
+ VALID_TYPES = [ '#', '^', '/', '=', '!', '<', '>', '&', '{' ]
49
+
50
+ def self.valid_types
51
+ @valid_types ||= Regexp.new(VALID_TYPES.map { |t| Regexp.escape(t) }.join('|') )
52
+ end
53
+
54
+ # Add a supported sigil type (with optional aliases) to the Parser.
55
+ #
56
+ # Requires a block, which will be sent the following parameters:
57
+ #
58
+ # * content - The raw content of the tag
59
+ # * fetch- A mustache context fetch expression for the content
60
+ # * padding - Indentation whitespace from the currently-parsed line
61
+ # * pre_match_position - Location of the scanner before a match was made
62
+ #
63
+ # The provided block will be evaluated against the current instance of
64
+ # Parser, and may append to the Parser's @result as needed.
65
+ def self.add_type(*types, &block)
66
+ types = types.map(&:to_s)
67
+ type, *aliases = types
68
+ method_name = "scan_tag_#{type}".to_sym
69
+ define_method(method_name, &block)
70
+ aliases.each { |a| alias_method "scan_tag_#{a}", method_name }
71
+ types.each { |t| VALID_TYPES << t unless VALID_TYPES.include?(t) }
72
+ @valid_types = nil
73
+ end
74
+
47
75
  # After these types of tags, all whitespace until the end of the line will
48
76
  # be skipped if they are the first (and only) non-whitespace content on
49
77
  # the line.
@@ -124,7 +152,7 @@ EOF
124
152
  # Since {{= rewrites ctag, we store the ctag which should be used
125
153
  # when parsing this specific tag.
126
154
  current_ctag = self.ctag
127
- type = @scanner.scan(/#|\^|\/|=|!|<|>|&|\{/)
155
+ type = @scanner.scan(self.class.valid_types)
128
156
  @scanner.skip(/\s*/)
129
157
 
130
158
  # ANY_CONTENT tags allow any character inside of them, while
@@ -143,41 +171,16 @@ EOF
143
171
  prev = @result
144
172
 
145
173
  # Based on the sigil, do what needs to be done.
146
- case type
147
- when '#'
148
- block = [:multi]
149
- @result << [:mustache, :section, fetch, offset, block]
150
- @sections << [content, position, @result]
151
- @result = block
152
- when '^'
153
- block = [:multi]
154
- @result << [:mustache, :inverted_section, fetch, offset, block]
155
- @sections << [content, position, @result]
156
- @result = block
157
- when '/'
158
- section, pos, result = @sections.pop
159
- raw = @scanner.pre_match[pos[3]...pre_match_position] + padding
160
- (@result = result).last << raw << [self.otag, self.ctag]
161
-
162
- if section.nil?
163
- error "Closing unopened #{content.inspect}"
164
- elsif section != content
165
- error "Unclosed section #{section.inspect}", pos
166
- end
167
- when '!'
168
- # ignore comments
169
- when '='
170
- self.otag, self.ctag = content.split(' ', 2)
171
- when '>', '<'
172
- @result << [:mustache, :partial, content, offset, padding]
173
- when '{', '&'
174
- # The closing } in unescaped tags is just a hack for
175
- # aesthetics.
176
- type = "}" if type == "{"
177
- @result << [:mustache, :utag, fetch, offset]
174
+ if type
175
+ # Method#call proves much faster than using send
176
+ method("scan_tag_#{type}").
177
+ call(content, fetch, padding, pre_match_position)
178
178
  else
179
179
  @result << [:mustache, :etag, fetch, offset]
180
180
  end
181
+ # The closing } in unescaped tags is just a hack for
182
+ # aesthetics.
183
+ type = "}" if type == "{"
181
184
 
182
185
  # Skip whitespace and any balancing sigils after the content
183
186
  # inside this tag.
@@ -263,5 +266,52 @@ EOF
263
266
  def error(message, pos = position)
264
267
  raise SyntaxError.new(message, pos)
265
268
  end
269
+
270
+ # These methods are called in `scan_tags`. Because they contain nonstandard
271
+ # characters in their method names, they are defined using define_method.
272
+
273
+ define_method 'scan_tag_#' do |content, fetch, padding, pre_match_position|
274
+ block = [:multi]
275
+ @result << [:mustache, :section, fetch, offset, block]
276
+ @sections << [content, position, @result]
277
+ @result = block
278
+ end
279
+
280
+ define_method 'scan_tag_^' do |content, fetch, padding, pre_match_position|
281
+ block = [:multi]
282
+ @result << [:mustache, :inverted_section, fetch, offset, block]
283
+ @sections << [content, position, @result]
284
+ @result = block
285
+ end
286
+
287
+ define_method 'scan_tag_/' do |content, fetch, padding, pre_match_position|
288
+ section, pos, result = @sections.pop
289
+ raw = @scanner.pre_match[pos[3]...pre_match_position] + padding
290
+ (@result = result).last << raw << [self.otag, self.ctag]
291
+
292
+ if section.nil?
293
+ error "Closing unopened #{content.inspect}"
294
+ elsif section != content
295
+ error "Unclosed section #{section.inspect}", pos
296
+ end
297
+ end
298
+
299
+ define_method 'scan_tag_!' do |content, fetch, padding, pre_match_position|
300
+ end
301
+
302
+ define_method 'scan_tag_=' do |content, fetch, padding, pre_match_position|
303
+ self.otag, self.ctag = content.split(' ', 2)
304
+ end
305
+
306
+ define_method 'scan_tag_>' do |content, fetch, padding, pre_match_position|
307
+ @result << [:mustache, :partial, content, offset, padding]
308
+ end
309
+ alias_method :'scan_tag_<', :'scan_tag_>'
310
+
311
+ define_method 'scan_tag_{' do |content, fetch, padding, pre_match_position|
312
+ @result << [:mustache, :utag, fetch, offset]
313
+ end
314
+ alias_method :'scan_tag_&', :'scan_tag_{'
315
+
266
316
  end
267
317
  end
@@ -138,7 +138,7 @@ class Mustache
138
138
  options[:namespace] ||= self.class
139
139
 
140
140
  unless options[:namespace].to_s.include? 'Views'
141
- options[:namespace] = options[:namespace].const_get(:Views)
141
+ options[:namespace] = options[:namespace].const_get(:Views) rescue Object
142
142
  end
143
143
 
144
144
  factory = Class.new(Mustache) do
@@ -54,5 +54,57 @@ class Mustache
54
54
  def tokens(src = @source)
55
55
  Parser.new.compile(src)
56
56
  end
57
+
58
+ # Simple recursive iterator for tokens
59
+ def self.recursor(toks, section, &block)
60
+ toks.map do |token|
61
+ next unless token.is_a? Array
62
+ if token[0] == :mustache
63
+ new_token, new_section, result, stop = yield(token, section)
64
+ [ result ] + ( stop ? [] : recursor(new_token, new_section, &block))
65
+ else
66
+ recursor(token, section, &block)
67
+ end
68
+ end
69
+ end
70
+
71
+ # Returns an array of tags
72
+ # Tags that belong to sections will be of the form `section1.tag`
73
+ def tags
74
+ Template.recursor(tokens, []) do |token, section|
75
+ if [:etag, :utag].include?(token[1])
76
+ [ new_token=nil, new_section=nil, result=((section + [token[2][2][0]]).join('.')), stop=true ]
77
+ elsif [:section, :inverted_section].include?(token[1])
78
+ [ new_token=token[4], new_section=(section + [token[2][2][0]]), result=nil, stop=false ]
79
+ else
80
+ [ new_token=token, new_section=section, result=nil, stop=false ]
81
+ end
82
+ end.flatten.reject(&:nil?).uniq
83
+ end
84
+
85
+ # Returns an array of sections
86
+ # Sections that belong to other sections will be of the form `section1.childsection`
87
+ def sections
88
+ Template.recursor(tokens, []) do |token, section|
89
+ if [:section, :inverted_section].include?(token[1])
90
+ new_section=(section + [token[2][2][0]])
91
+ [ new_token=token[4], new_section, result=new_section.join('.'), stop=false ]
92
+ else
93
+ [ new_token=token, new_section=section, result=nil, stop=false ]
94
+ end
95
+ end.flatten.reject(&:nil?).uniq
96
+ end
97
+
98
+ # Returns an array of partials
99
+ # Partials that belong to sections are included, but the section name is not preserved
100
+ def partials
101
+ Template.recursor(tokens, []) do |token, section|
102
+ if token[1] == :partial
103
+ [ new_token=token, new_section=section, result=token[2], stop=true ]
104
+ else
105
+ [ new_token=token, new_section=section, result=nil, stop=false ]
106
+ end
107
+ end.flatten.reject(&:nil?).uniq
108
+ end
57
109
  end
58
110
  end
@@ -1,3 +1,3 @@
1
1
  class Mustache
2
- Version = VERSION = '0.99.5'
2
+ Version = VERSION = '0.99.6'
3
3
  end
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "MUSTACHE" "1" "August 2011" "DEFUNKT" "Mustache Manual"
4
+ .TH "MUSTACHE" "1" "February 2014" "DEFUNKT" "Mustache Manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBmustache\fR \- Mustache processor
@@ -23,7 +23,7 @@ Mustache is a logic\-less templating system for HTML, config files, anything\.
23
23
  The \fBmustache\fR command processes a Mustache template preceded by YAML frontmatter from standard input and prints one or more documents to standard output\.
24
24
  .
25
25
  .P
26
- YAML frontmatter beings with \fB\-\-\-\fR on a single line, followed by YAML, ending with another \fB\-\-\-\fR on a single line, e\.g\.
26
+ YAML frontmatter begins with \fB\-\-\-\fR on a single line, followed by YAML, ending with another \fB\-\-\-\fR on a single line, e\.g\.
27
27
  .
28
28
  .IP "" 4
29
29
  .
@@ -124,7 +124,7 @@ Print the compiled Ruby version of a given template\. This is the code that is a
124
124
  .
125
125
  .TP
126
126
  \fB\-t\fR, \fB\-\-tokens\fR
127
- Print the tokenized form of a given Mustache template\. This can be used to understand how Mustache parses a template\. The tokens are handed to a generator which compiles them into a Ruby string\. Syntax errors and confused tags, therefor, can probably be identified by examining the tokens produced\.
127
+ Print the tokenized form of a given Mustache template\. This can be used to understand how Mustache parses a template\. The tokens are handed to a generator which compiles them into a Ruby string\. Syntax errors and confused tags, therefore, can probably be identified by examining the tokens produced\.
128
128
  .
129
129
  .SH "INSTALLATION"
130
130
  If you have RubyGems installed:
@@ -162,4 +162,4 @@ Mustache is Copyright (C) 2009 Chris Wanstrath
162
162
  Original CTemplate by Google
163
163
  .
164
164
  .SH "SEE ALSO"
165
- mustache(5), gem(1), \fIhttp://mustache\.github\.com/\fR
165
+ mustache(5), gem(1), \fIhttp://mustache\.github\.io/\fR
@@ -90,7 +90,7 @@ anything.</p>
90
90
  frontmatter from standard input and prints one or more documents to
91
91
  standard output.</p>
92
92
 
93
- <p>YAML frontmatter beings with <code>---</code> on a single line, followed by YAML,
93
+ <p>YAML frontmatter begins with <code>---</code> on a single line, followed by YAML,
94
94
  ending with another <code>---</code> on a single line, e.g.</p>
95
95
 
96
96
  <pre><code>---
@@ -102,7 +102,7 @@ names: [ {name: chris}, {name: mark}, {name: scott} ]
102
102
  should work fine.</p>
103
103
 
104
104
  <p>After the frontmatter should come any valid Mustache template. See
105
- <a href="mustache.5.ron.html" class="man-ref">mustache<span class="s">(5)</span></a> for an overview of Mustache templates.</p>
105
+ <a class="man-ref" href="mustache.5.ron.html">mustache<span class="s">(5)</span></a> for an overview of Mustache templates.</p>
106
106
 
107
107
  <p>For example:</p>
108
108
 
@@ -165,7 +165,7 @@ Mustache's internals.</p></dd>
165
165
  <dt><code>-t</code>, <code>--tokens</code></dt><dd><p>Print the tokenized form of a given Mustache template. This can be
166
166
  used to understand how Mustache parses a template. The tokens are
167
167
  handed to a generator which compiles them into a Ruby
168
- string. Syntax errors and confused tags, therefor, can probably be
168
+ string. Syntax errors and confused tags, therefore, can probably be
169
169
  identified by examining the tokens produced.</p></dd>
170
170
  </dl>
171
171
 
@@ -198,13 +198,13 @@ data
198
198
 
199
199
  <h2 id="SEE-ALSO">SEE ALSO</h2>
200
200
 
201
- <p><a href="mustache.5.ron.html" class="man-ref">mustache<span class="s">(5)</span></a>, <span class="man-ref">gem<span class="s">(1)</span></span>,
202
- <a href="http://mustache.github.com/" data-bare-link="true">http://mustache.github.com/</a></p>
201
+ <p><a class="man-ref" href="mustache.5.ron.html">mustache<span class="s">(5)</span></a>, <span class="man-ref">gem<span class="s">(1)</span></span>,
202
+ <a href="http://mustache.github.io/" data-bare-link="true">http://mustache.github.io/</a></p>
203
203
 
204
204
 
205
205
  <ol class='man-decor man-foot man foot'>
206
206
  <li class='tl'>DEFUNKT</li>
207
- <li class='tc'>August 2011</li>
207
+ <li class='tc'>February 2014</li>
208
208
  <li class='tr'>mustache(1)</li>
209
209
  </ol>
210
210
 
@@ -17,7 +17,7 @@ The `mustache` command processes a Mustache template preceded by YAML
17
17
  frontmatter from standard input and prints one or more documents to
18
18
  standard output.
19
19
 
20
- YAML frontmatter beings with `---` on a single line, followed by YAML,
20
+ YAML frontmatter begins with `---` on a single line, followed by YAML,
21
21
  ending with another `---` on a single line, e.g.
22
22
 
23
23
  ---
@@ -90,7 +90,7 @@ YAML frontmatter you provide. It can do a few other things, however.
90
90
  Print the tokenized form of a given Mustache template. This can be
91
91
  used to understand how Mustache parses a template. The tokens are
92
92
  handed to a generator which compiles them into a Ruby
93
- string. Syntax errors and confused tags, therefor, can probably be
93
+ string. Syntax errors and confused tags, therefore, can probably be
94
94
  identified by examining the tokens produced.
95
95
 
96
96
 
@@ -124,4 +124,4 @@ Original CTemplate by Google
124
124
  ## SEE ALSO
125
125
 
126
126
  mustache(5), gem(1),
127
- <http://mustache.github.com/>
127
+ <http://mustache.github.io/>
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "MUSTACHE" "5" "August 2011" "DEFUNKT" "Mustache Manual"
4
+ .TH "MUSTACHE" "5" "April 2014" "DEFUNKT" "Mustache Manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBmustache\fR \- Logic\-less templates\.
@@ -66,7 +66,7 @@ We call it "logic\-less" because there are no if statements, else clauses, or fo
66
66
  Tags are indicated by the double mustaches\. \fB{{person}}\fR is a tag, as is \fB{{#person}}\fR\. In both examples, we\'d refer to \fBperson\fR as the key or tag key\. Let\'s talk about the different types of tags\.
67
67
  .
68
68
  .SS "Variables"
69
- The most basic tag type is the variable\. A \fB{{name}}\fR tag in a basic template will try to find the \fBname\fR key in the current context\. If there is no \fBname\fR key, nothing will be rendered\.
69
+ The most basic tag type is the variable\. A \fB{{name}}\fR tag in a basic template will try to find the \fBname\fR key in the current context\. If there is no \fBname\fR key, the parent contexts will be checked recursively\. If the top context is reached and the \fBname\fR key is still not found, nothing will be rendered\.
70
70
  .
71
71
  .P
72
72
  All variables are HTML escaped by default\. If you want to return unescaped HTML, use the triple mustache: \fB{{{name}}}\fR\.
@@ -148,9 +148,9 @@ Template:
148
148
  .nf
149
149
 
150
150
  Shown\.
151
- {{#nothin}}
151
+ {{#person}}
152
152
  Never shown!
153
- {{/nothin}}
153
+ {{/person}}
154
154
  .
155
155
  .fi
156
156
  .
@@ -164,7 +164,7 @@ Hash:
164
164
  .nf
165
165
 
166
166
  {
167
- "person": true,
167
+ "person": false
168
168
  }
169
169
  .
170
170
  .fi
@@ -219,7 +219,7 @@ Hash:
219
219
  "repo": [
220
220
  { "name": "resque" },
221
221
  { "name": "hub" },
222
- { "name": "rip" },
222
+ { "name": "rip" }
223
223
  ]
224
224
  }
225
225
  .
@@ -273,7 +273,7 @@ Hash:
273
273
  {
274
274
  "name": "Willy",
275
275
  "wrapped": function() {
276
- return function(text) {
276
+ return function(text, render) {
277
277
  return "<b>" + render(text) + "</b>"
278
278
  }
279
279
  }
@@ -536,4 +536,4 @@ Mustache is Copyright (C) 2009 Chris Wanstrath
536
536
  Original CTemplate by Google
537
537
  .
538
538
  .SH "SEE ALSO"
539
- mustache(1), \fIhttp://mustache\.github\.com/\fR
539
+ mustache(1), \fIhttp://mustache\.github\.io/\fR
@@ -121,7 +121,9 @@ or tag key. Let's talk about the different types of tags.</p>
121
121
 
122
122
  <p>The most basic tag type is the variable. A <code>{{name}}</code> tag in a basic
123
123
  template will try to find the <code>name</code> key in the current context. If
124
- there is no <code>name</code> key, nothing will be rendered.</p>
124
+ there is no <code>name</code> key, the parent contexts will be checked recursively.
125
+ If the top context is reached and the <code>name</code> key is still not found,
126
+ nothing will be rendered.</p>
125
127
 
126
128
  <p>All variables are HTML escaped by default. If you want to return
127
129
  unescaped HTML, use the triple mustache: <code>{{{name}}}</code>.</p>
@@ -175,15 +177,15 @@ list, the HTML between the pound and slash will not be displayed.</p>
175
177
  <p>Template:</p>
176
178
 
177
179
  <pre><code>Shown.
178
- {{#nothin}}
180
+ {{#person}}
179
181
  Never shown!
180
- {{/nothin}}
182
+ {{/person}}
181
183
  </code></pre>
182
184
 
183
185
  <p>Hash:</p>
184
186
 
185
187
  <pre><code>{
186
- "person": true,
188
+ "person": false
187
189
  }
188
190
  </code></pre>
189
191
 
@@ -215,7 +217,7 @@ loop over collections.</p>
215
217
  "repo": [
216
218
  { "name": "resque" },
217
219
  { "name": "hub" },
218
- { "name": "rip" },
220
+ { "name": "rip" }
219
221
  ]
220
222
  }
221
223
  </code></pre>
@@ -247,7 +249,7 @@ filters or caching.</p>
247
249
  <pre><code>{
248
250
  "name": "Willy",
249
251
  "wrapped": function() {
250
- return function(text) {
252
+ return function(text, render) {
251
253
  return "&lt;b&gt;" + render(text) + "&lt;/b&gt;"
252
254
  }
253
255
  }
@@ -407,13 +409,13 @@ markup."</p>
407
409
 
408
410
  <h2 id="SEE-ALSO">SEE ALSO</h2>
409
411
 
410
- <p><a href="mustache.1.ron.html" class="man-ref">mustache<span class="s">(1)</span></a>,
411
- <a href="http://mustache.github.com/" data-bare-link="true">http://mustache.github.com/</a></p>
412
+ <p><a class="man-ref" href="mustache.1.ron.html">mustache<span class="s">(1)</span></a>,
413
+ <a href="http://mustache.github.io/" data-bare-link="true">http://mustache.github.io/</a></p>
412
414
 
413
415
 
414
416
  <ol class='man-decor man-foot man foot'>
415
417
  <li class='tl'>DEFUNKT</li>
416
- <li class='tc'>August 2011</li>
418
+ <li class='tc'>April 2014</li>
417
419
  <li class='tr'>mustache(5)</li>
418
420
  </ol>
419
421
 
@@ -50,7 +50,9 @@ or tag key. Let's talk about the different types of tags.
50
50
 
51
51
  The most basic tag type is the variable. A `{{name}}` tag in a basic
52
52
  template will try to find the `name` key in the current context. If
53
- there is no `name` key, nothing will be rendered.
53
+ there is no `name` key, the parent contexts will be checked recursively.
54
+ If the top context is reached and the `name` key is still not found,
55
+ nothing will be rendered.
54
56
 
55
57
  All variables are HTML escaped by default. If you want to return
56
58
  unescaped HTML, use the triple mustache: `{{{name}}}`.
@@ -102,14 +104,14 @@ list, the HTML between the pound and slash will not be displayed.
102
104
  Template:
103
105
 
104
106
  Shown.
105
- {{#nothin}}
107
+ {{#person}}
106
108
  Never shown!
107
- {{/nothin}}
109
+ {{/person}}
108
110
 
109
111
  Hash:
110
112
 
111
113
  {
112
- "person": true,
114
+ "person": false
113
115
  }
114
116
 
115
117
  Output:
@@ -138,7 +140,7 @@ Hash:
138
140
  "repo": [
139
141
  { "name": "resque" },
140
142
  { "name": "hub" },
141
- { "name": "rip" },
143
+ { "name": "rip" }
142
144
  ]
143
145
  }
144
146
 
@@ -167,7 +169,7 @@ Hash:
167
169
  {
168
170
  "name": "Willy",
169
171
  "wrapped": function() {
170
- return function(text) {
172
+ return function(text, render) {
171
173
  return "<b>" + render(text) + "</b>"
172
174
  }
173
175
  }
@@ -321,4 +323,4 @@ Original CTemplate by Google
321
323
  ## SEE ALSO
322
324
 
323
325
  mustache(1),
324
- <http://mustache.github.com/>
326
+ <http://mustache.github.io/>