mustache 1.0.3 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/README.md +108 -89
- data/lib/mustache.rb +13 -4
- data/lib/mustache/context.rb +1 -0
- data/lib/mustache/generator.rb +36 -20
- data/lib/mustache/parser.rb +36 -17
- data/lib/mustache/template.rb +5 -4
- data/lib/mustache/version.rb +1 -1
- data/man/mustache.1 +3 -3
- data/man/mustache.1.html +3 -3
- data/man/mustache.1.ron +2 -2
- data/man/mustache.5 +1 -1
- data/man/mustache.5.html +1 -1
- data/test/helper.rb +5 -3
- data/test/mustache_test.rb +47 -2
- data/test/partial_test.rb +13 -0
- metadata +21 -30
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MGYwNTg4YTNlMGIzMDFlM2RlZWRlYjgxOWVkYzVmMjBkYTY0NjJlMg==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bf94eeecd19f735037d7bbb26dec6b31fd744220
|
4
|
+
data.tar.gz: 1950b718fced739f53562898d3577a10ca88cdbf
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
ODk0MDY3NTliYjM2NGI1OGUzMzZiNDkzNzA4NjEzNWJhMGRhZGFiZmUwYjJj
|
11
|
-
ODYzNjY3MWU0MDg2NjUzMzdkYTcwZGZhOTk4NWQ1MWZhYzBlNGQ=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NDA2ZDRiNjRlYTg3MjRkZjhmNWFjZDAyMjY3YzU1YzM0NTU4MWNlMzkzMmI0
|
14
|
-
MjAxMjAxOWYyNDdmYWE5MzEwODYzYzExZjBmM2VkN2E3YzdmODYxNGI2NTc3
|
15
|
-
N2U3ZGExOTcxMmE3MDBmMTdmMWI1YmUzNmE4YTFlMTdiMjQwNmM=
|
6
|
+
metadata.gz: 2aa2853641590267b49b7264f8592fed44f3fa430ea10e60ae3ce8b58a5fadea3b532f256b70229a0fbd62835176ead87b8dff0d66ac73750af603c9739e6587
|
7
|
+
data.tar.gz: 31a31d089046ab7d11b6541a02b588d92c26a6b5879185203ddc4ffedd64a41cc6b0651b818066333ee9af4000754a8f1d3885b5647895390ebe3e62d65532ae
|
data/README.md
CHANGED
@@ -44,10 +44,12 @@ in my HTML, or putting JavaScript in my HTML.
|
|
44
44
|
Install the gem locally with:
|
45
45
|
|
46
46
|
$ gem install mustache
|
47
|
-
|
48
|
-
Or add it to your `gemspec`:
|
49
47
|
|
50
|
-
|
48
|
+
Or add it to your `Gemfile`:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
gem "mustache", "~> 1.0"
|
52
|
+
```
|
51
53
|
|
52
54
|
|
53
55
|
## Usage
|
@@ -56,28 +58,30 @@ Quick example:
|
|
56
58
|
|
57
59
|
>> require 'mustache'
|
58
60
|
=> true
|
59
|
-
>> Mustache.render("Hello {{planet}}", :
|
61
|
+
>> Mustache.render("Hello {{planet}}", planet: "World!")
|
60
62
|
=> "Hello World!"
|
61
63
|
|
62
64
|
We've got an `examples` folder but here's the canonical one:
|
63
65
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
66
|
+
```ruby
|
67
|
+
class Simple < Mustache
|
68
|
+
def name
|
69
|
+
"Chris"
|
70
|
+
end
|
68
71
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
+
def value
|
73
|
+
10_000
|
74
|
+
end
|
72
75
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
+
def taxed_value
|
77
|
+
value * 0.6
|
78
|
+
end
|
76
79
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
80
|
+
def in_ca
|
81
|
+
true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
```
|
81
85
|
|
82
86
|
We simply create a normal Ruby class and define methods. Some methods
|
83
87
|
reference others, some return values, some return only booleans.
|
@@ -92,9 +96,9 @@ Now let's write the template:
|
|
92
96
|
|
93
97
|
This template references our view methods. To bring it all together,
|
94
98
|
here's the code to render actual HTML;
|
95
|
-
|
96
|
-
|
97
|
-
|
99
|
+
```ruby
|
100
|
+
Simple.render
|
101
|
+
```
|
98
102
|
Which returns the following:
|
99
103
|
|
100
104
|
Hello Chris
|
@@ -114,7 +118,7 @@ the `mustache(5)` manpage or
|
|
114
118
|
## Escaping
|
115
119
|
|
116
120
|
Mustache does escape all values when using the standard double
|
117
|
-
Mustache syntax. Characters which will be escaped: `& \ " < >` (as
|
121
|
+
Mustache syntax. Characters which will be escaped: `& \ " < >` (as
|
118
122
|
well as `'` in Ruby `>= 2.0`). To disable escaping, simply use triple
|
119
123
|
mustaches like `{{{unescaped_variable}}}`.
|
120
124
|
|
@@ -136,11 +140,12 @@ Given this template (winner.mustache):
|
|
136
140
|
|
137
141
|
We can fill in the values at will:
|
138
142
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
143
|
+
```ruby
|
144
|
+
view = Winner.new
|
145
|
+
view[:name] = 'George'
|
146
|
+
view[:value] = 100
|
147
|
+
view.render
|
148
|
+
```
|
144
149
|
Which returns:
|
145
150
|
|
146
151
|
Hello George
|
@@ -148,11 +153,10 @@ Which returns:
|
|
148
153
|
|
149
154
|
We can re-use the same object, too:
|
150
155
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
+
```ruby
|
157
|
+
view[:name] = 'Tony'
|
158
|
+
view.render # => Hello Tony\nYou have just won 100 bucks!
|
159
|
+
```
|
156
160
|
|
157
161
|
## Templates
|
158
162
|
|
@@ -165,33 +169,38 @@ follows the classic Ruby naming convention.
|
|
165
169
|
You can set the search path using `Mustache.template_path`. It can be set on a
|
166
170
|
class by class basis:
|
167
171
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
172
|
+
```ruby
|
173
|
+
class Simple < Mustache
|
174
|
+
self.template_path = __dir__
|
175
|
+
end
|
176
|
+
```
|
173
177
|
Now `Simple` will look for `simple.mustache` in the directory it resides
|
174
178
|
in, no matter the cwd.
|
175
179
|
|
176
180
|
If you want to just change what template is used you can set
|
177
181
|
`Mustache.template_file` directly:
|
178
182
|
|
179
|
-
|
180
|
-
|
183
|
+
```ruby
|
184
|
+
Simple.template_file = './blah.mustache'
|
185
|
+
```
|
181
186
|
Mustache also allows you to define the extension it'll use.
|
182
187
|
|
183
|
-
|
184
|
-
|
188
|
+
```ruby
|
189
|
+
Simple.template_extension = 'xml'
|
190
|
+
```
|
185
191
|
Given all other defaults, the above line will cause Mustache to look
|
186
192
|
for './blah.xml'
|
187
193
|
|
188
194
|
Feel free to set the template directly:
|
189
195
|
|
190
|
-
|
196
|
+
```ruby
|
197
|
+
Simple.template = 'Hi {{person}}!'
|
198
|
+
```
|
191
199
|
|
192
200
|
Or set a different template for a single instance:
|
193
|
-
|
194
|
-
|
201
|
+
```ruby
|
202
|
+
Simple.new.template = 'Hi {{person}}!'
|
203
|
+
```
|
195
204
|
|
196
205
|
Whatever works.
|
197
206
|
|
@@ -211,46 +220,50 @@ you want to use in all your views? No problem.
|
|
211
220
|
|
212
221
|
This is just Ruby, after all.
|
213
222
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
223
|
+
```ruby
|
224
|
+
module ViewHelpers
|
225
|
+
def gravatar
|
226
|
+
gravatar_id = Digest::MD5.hexdigest(self[:email].to_s.strip.downcase)
|
227
|
+
gravatar_for_id(gravatar_id)
|
228
|
+
end
|
219
229
|
|
220
|
-
|
221
|
-
|
222
|
-
|
230
|
+
def gravatar_for_id(gid, size = 30)
|
231
|
+
"#{gravatar_host}/avatar/#{gid}?s=#{size}"
|
232
|
+
end
|
223
233
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
234
|
+
def gravatar_host
|
235
|
+
@ssl ? 'https://secure.gravatar.com' : 'http://www.gravatar.com'
|
236
|
+
end
|
237
|
+
end
|
238
|
+
```
|
228
239
|
|
229
240
|
Then just include it:
|
230
241
|
|
231
|
-
|
232
|
-
|
242
|
+
```ruby
|
243
|
+
class Simple < Mustache
|
244
|
+
include ViewHelpers
|
233
245
|
|
234
|
-
|
235
|
-
|
236
|
-
|
246
|
+
def name
|
247
|
+
"Chris"
|
248
|
+
end
|
237
249
|
|
238
|
-
|
239
|
-
|
240
|
-
|
250
|
+
def value
|
251
|
+
10_000
|
252
|
+
end
|
241
253
|
|
242
|
-
|
243
|
-
|
244
|
-
|
254
|
+
def taxed_value
|
255
|
+
value * 0.6
|
256
|
+
end
|
245
257
|
|
246
|
-
|
247
|
-
|
248
|
-
|
258
|
+
def in_ca
|
259
|
+
true
|
260
|
+
end
|
249
261
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
262
|
+
def users
|
263
|
+
User.all
|
264
|
+
end
|
265
|
+
end
|
266
|
+
```
|
254
267
|
|
255
268
|
Great, but what about that `@ssl` ivar in `gravatar_host`? There are
|
256
269
|
many ways we can go about setting it.
|
@@ -259,19 +272,21 @@ Here's an example which illustrates a key feature of Mustache: you
|
|
259
272
|
are free to use the `initialize` method just as you would in any
|
260
273
|
normal class.
|
261
274
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
def initialize(ssl = false)
|
266
|
-
@ssl = ssl
|
267
|
-
end
|
275
|
+
```ruby
|
276
|
+
class Simple < Mustache
|
277
|
+
include ViewHelpers
|
268
278
|
|
269
|
-
|
270
|
-
|
279
|
+
def initialize(ssl = false)
|
280
|
+
@ssl = ssl
|
281
|
+
end
|
282
|
+
end
|
283
|
+
```
|
271
284
|
|
272
285
|
Now:
|
273
286
|
|
274
|
-
|
287
|
+
```ruby
|
288
|
+
Simple.new(request.ssl?).render
|
289
|
+
```
|
275
290
|
|
276
291
|
Finally, our template might look like this:
|
277
292
|
|
@@ -286,7 +301,7 @@ Finally, our template might look like this:
|
|
286
301
|
|
287
302
|
### Sinatra
|
288
303
|
|
289
|
-
Sinatra integration is available with the
|
304
|
+
Sinatra integration is available with the
|
290
305
|
[mustache-sinatra gem](https://github.com/mustache/mustache-sinatra).
|
291
306
|
|
292
307
|
An example Sinatra application is also provided:
|
@@ -305,13 +320,17 @@ contained in a hash set using `set :mustache, hash`.
|
|
305
320
|
Mustache also provides a `Rack::Bug` panel.
|
306
321
|
First you have to install the `rack-bug-mustache_panel` gem, then in your `config.ru` add the following code:
|
307
322
|
|
308
|
-
|
309
|
-
|
323
|
+
```ruby
|
324
|
+
require 'rack/bug/panels/mustache_panel'
|
325
|
+
use Rack::Bug::MustachePanel
|
326
|
+
```
|
310
327
|
|
311
328
|
Using Rails? Add this to your initializer or environment file:
|
312
329
|
|
313
|
-
|
314
|
-
|
330
|
+
```ruby
|
331
|
+
require 'rack/bug/panels/mustache_panel'
|
332
|
+
config.middleware.use "Rack::Bug::MustachePanel"
|
333
|
+
```
|
315
334
|
|
316
335
|
![Rack::Bug][5]
|
317
336
|
|
@@ -390,6 +409,6 @@ or IRC:
|
|
390
409
|
[is]: https://github.com/mustache/mustache/issues
|
391
410
|
[irc]: irc://irc.freenode.net/#{
|
392
411
|
[vim]: https://github.com/mustache/vim-mustache-handlebars
|
393
|
-
[emacs]: https://github.com/mustache/
|
412
|
+
[emacs]: https://github.com/mustache/emacs
|
394
413
|
[tmbundle]: https://github.com/defunkt/Mustache.tmbundle
|
395
414
|
[diff]: https://gist.github.com/defunkt/345490
|
data/lib/mustache.rb
CHANGED
@@ -74,6 +74,12 @@ require 'mustache/utils'
|
|
74
74
|
#
|
75
75
|
class Mustache
|
76
76
|
|
77
|
+
# Initialize a new mustache instance.
|
78
|
+
# @param [Hash] options An options hash
|
79
|
+
def initialize(options = {})
|
80
|
+
@options = options
|
81
|
+
end
|
82
|
+
|
77
83
|
# Instantiates an instance of this class and calls `render` with
|
78
84
|
# the passed args.
|
79
85
|
#
|
@@ -266,13 +272,16 @@ class Mustache
|
|
266
272
|
Mustache::Utils::String.new(classified).underscore(view_namespace)
|
267
273
|
end
|
268
274
|
|
269
|
-
# @param [Template,String] obj
|
270
|
-
|
271
|
-
|
275
|
+
# @param [Template,String] obj Turns `obj` into a template
|
276
|
+
# @param [Hash] options Options for template creation
|
277
|
+
def self.templateify(obj, options = {})
|
278
|
+
obj.is_a?(Template) ? obj : Template.new(obj, options)
|
272
279
|
end
|
273
280
|
|
274
281
|
def templateify(obj)
|
275
|
-
self.
|
282
|
+
opts = {:partial_resolver => self.method(:partial)}
|
283
|
+
opts.merge!(@options) if @options.is_a?(Hash)
|
284
|
+
self.class.templateify(obj, opts)
|
276
285
|
end
|
277
286
|
|
278
287
|
# Return the value of the configuration setting on the superclass, or return
|
data/lib/mustache/context.rb
CHANGED
@@ -159,6 +159,7 @@ class Mustache
|
|
159
159
|
def find_in_hash(obj, key, default)
|
160
160
|
return obj[key] if obj.has_key?(key)
|
161
161
|
return obj[key.to_s] if obj.has_key?(key.to_s)
|
162
|
+
return obj[key] if obj.respond_to?(:default_proc) && obj.default_proc && obj[key]
|
162
163
|
|
163
164
|
# If default is :__missing then we are from #fetch which is hunting through the stack
|
164
165
|
# If default is nil then we are reducing dot notation
|
data/lib/mustache/generator.rb
CHANGED
@@ -27,9 +27,10 @@ class Mustache
|
|
27
27
|
# $ mustache --compile test.mustache
|
28
28
|
# "Hi #{CGI.escapeHTML(ctx[:thing].to_s)}!\n"
|
29
29
|
class Generator
|
30
|
-
# Options
|
30
|
+
# Options can be used to manipulate the resulting ruby code string behavior.
|
31
31
|
def initialize(options = {})
|
32
32
|
@options = options
|
33
|
+
@option_static_lambdas = options[:static_lambdas] == true
|
33
34
|
end
|
34
35
|
|
35
36
|
# Given an array of tokens, returns an interpolatable Ruby string.
|
@@ -104,13 +105,14 @@ class Mustache
|
|
104
105
|
# string we can use.
|
105
106
|
code = compile(content)
|
106
107
|
|
107
|
-
#
|
108
|
-
#
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
108
|
+
# Lambda handling - default handling is to dynamically interpret
|
109
|
+
# the returned lambda result as mustache source
|
110
|
+
proc_handling = if @option_static_lambdas
|
111
|
+
<<-compiled
|
112
|
+
v.call(lambda {|v| #{code}}.call(v)).to_s
|
113
|
+
compiled
|
114
|
+
else
|
115
|
+
<<-compiled
|
114
116
|
t = Mustache::Template.new(v.call(#{raw.inspect}).to_s)
|
115
117
|
def t.tokens(src=@source)
|
116
118
|
p = Mustache::Parser.new
|
@@ -118,12 +120,22 @@ class Mustache
|
|
118
120
|
p.compile(src)
|
119
121
|
end
|
120
122
|
t.render(ctx.dup)
|
121
|
-
|
122
|
-
|
123
|
-
v = [v] unless v.is_a?(Array) || v.is_a?(Mustache::Enumerable) || defined?(Enumerator) && v.is_a?(Enumerator)
|
123
|
+
compiled
|
124
|
+
end
|
124
125
|
|
125
|
-
|
126
|
-
|
126
|
+
# Compile the Ruby for this section now that we know what's
|
127
|
+
# inside the section.
|
128
|
+
ev(<<-compiled)
|
129
|
+
case v = #{compile!(name)}
|
130
|
+
when NilClass, FalseClass
|
131
|
+
when TrueClass
|
132
|
+
#{code}
|
133
|
+
when Proc
|
134
|
+
#{proc_handling}
|
135
|
+
when Array, Enumerator, Mustache::Enumerable
|
136
|
+
v.map { |h| ctx.push(h); r = #{code}; ctx.pop; r }.join
|
137
|
+
else
|
138
|
+
ctx.push(v); r = #{code}; ctx.pop; r
|
127
139
|
end
|
128
140
|
compiled
|
129
141
|
end
|
@@ -157,7 +169,7 @@ class Mustache
|
|
157
169
|
ev(<<-compiled)
|
158
170
|
v = #{compile!(name)}
|
159
171
|
if v.is_a?(Proc)
|
160
|
-
v = Mustache::Template.new(v.call.to_s).render(ctx.dup)
|
172
|
+
v = #{@option_static_lambdas ? 'v.call' : 'Mustache::Template.new(v.call.to_s).render(ctx.dup)'}
|
161
173
|
end
|
162
174
|
v.to_s
|
163
175
|
compiled
|
@@ -168,7 +180,7 @@ class Mustache
|
|
168
180
|
ev(<<-compiled)
|
169
181
|
v = #{compile!(name)}
|
170
182
|
if v.is_a?(Proc)
|
171
|
-
v = Mustache::Template.new(v.call.to_s).render(ctx.dup)
|
183
|
+
v = #{@option_static_lambdas ? 'v.call' : 'Mustache::Template.new(v.call.to_s).render(ctx.dup)'}
|
172
184
|
end
|
173
185
|
ctx.escapeHTML(v.to_s)
|
174
186
|
compiled
|
@@ -180,11 +192,15 @@ class Mustache
|
|
180
192
|
names = names.map { |n| n.to_sym }
|
181
193
|
|
182
194
|
initial, *rest = names
|
183
|
-
|
184
|
-
|
185
|
-
value && ctx.find(value, key)
|
186
|
-
|
187
|
-
|
195
|
+
if rest.any?
|
196
|
+
<<-compiled
|
197
|
+
#{rest.inspect}.reduce(ctx[#{initial.inspect}]) { |value, key| value && ctx.find(value, key) }
|
198
|
+
compiled
|
199
|
+
else
|
200
|
+
<<-compiled
|
201
|
+
ctx[#{initial.inspect}]
|
202
|
+
compiled
|
203
|
+
end
|
188
204
|
end
|
189
205
|
|
190
206
|
# An interpolation-friendly version of a string, for use within a
|
data/lib/mustache/parser.rb
CHANGED
@@ -84,22 +84,35 @@ EOF
|
|
84
84
|
# the rest only allow ALLOWED_CONTENT.
|
85
85
|
ANY_CONTENT = [ '!', '=' ].map(&:freeze)
|
86
86
|
|
87
|
-
|
87
|
+
attr_reader :otag, :ctag
|
88
88
|
|
89
89
|
# Accepts an options hash which does nothing but may be used in
|
90
90
|
# the future.
|
91
91
|
def initialize(options = {})
|
92
|
-
@options =
|
92
|
+
@options = options
|
93
|
+
@option_inline_partials_at_compile_time = options[:inline_partials_at_compile_time]
|
94
|
+
if @option_inline_partials_at_compile_time
|
95
|
+
@partial_resolver = options[:partial_resolver]
|
96
|
+
raise ArgumentError.new "Missing or invalid partial_resolver" unless @partial_resolver.respond_to? :call
|
97
|
+
end
|
98
|
+
|
99
|
+
# Initialize default tags
|
100
|
+
self.otag ||= '{{'
|
101
|
+
self.ctag ||= '}}'
|
93
102
|
end
|
94
103
|
|
95
104
|
# The opening tag delimiter. This may be changed at runtime.
|
96
|
-
def otag
|
97
|
-
|
105
|
+
def otag=(value)
|
106
|
+
regex = regexp value
|
107
|
+
@otag_regex = /([ \t]*)?#{regex}/
|
108
|
+
@otag_not_regex = /(^[ \t]*)?#{regex}/
|
109
|
+
@otag = value
|
98
110
|
end
|
99
111
|
|
100
112
|
# The closing tag delimiter. This too may be changed at runtime.
|
101
|
-
def ctag
|
102
|
-
@
|
113
|
+
def ctag=(value)
|
114
|
+
@ctag_regex = regexp value
|
115
|
+
@ctag = value
|
103
116
|
end
|
104
117
|
|
105
118
|
# Given a string template, returns an array of tokens.
|
@@ -134,9 +147,9 @@ EOF
|
|
134
147
|
private
|
135
148
|
|
136
149
|
|
137
|
-
def content_tags type,
|
150
|
+
def content_tags type, current_ctag_regex
|
138
151
|
if ANY_CONTENT.include?(type)
|
139
|
-
r = /\s*#{regexp(type)}?#{
|
152
|
+
r = /\s*#{regexp(type)}?#{current_ctag_regex}/
|
140
153
|
scan_until_exclusive(r)
|
141
154
|
else
|
142
155
|
@scanner.scan(ALLOWED_CONTENT)
|
@@ -147,8 +160,8 @@ EOF
|
|
147
160
|
send("scan_tag_#{type}", content, fetch, padding, pre_match_position)
|
148
161
|
end
|
149
162
|
|
150
|
-
def find_closing_tag scanner,
|
151
|
-
error "Unclosed tag" unless scanner.scan(
|
163
|
+
def find_closing_tag scanner, current_ctag_regex
|
164
|
+
error "Unclosed tag" unless scanner.scan(current_ctag_regex)
|
152
165
|
end
|
153
166
|
|
154
167
|
# Find {{mustaches}} and add them to the @result array.
|
@@ -158,7 +171,7 @@ EOF
|
|
158
171
|
pre_match_position = @scanner.pos
|
159
172
|
last_index = @result.length
|
160
173
|
|
161
|
-
return unless @scanner.scan
|
174
|
+
return unless @scanner.scan @otag_regex
|
162
175
|
padding = @scanner[1] || ''
|
163
176
|
|
164
177
|
# Don't touch the preceding whitespace unless we're matching the start
|
@@ -171,13 +184,13 @@ EOF
|
|
171
184
|
|
172
185
|
# Since {{= rewrites ctag, we store the ctag which should be used
|
173
186
|
# when parsing this specific tag.
|
174
|
-
|
187
|
+
current_ctag_regex = @ctag_regex
|
175
188
|
type = @scanner.scan(self.class.valid_types)
|
176
189
|
@scanner.skip(/\s*/)
|
177
190
|
|
178
191
|
# ANY_CONTENT tags allow any character inside of them, while
|
179
192
|
# other tags (such as variables) are more strict.
|
180
|
-
content = content_tags(type,
|
193
|
+
content = content_tags(type, current_ctag_regex)
|
181
194
|
|
182
195
|
# We found {{ but we can't figure out what's going on inside.
|
183
196
|
error "Illegal content in tag" if content.empty?
|
@@ -196,7 +209,7 @@ EOF
|
|
196
209
|
@scanner.skip(/\s+/)
|
197
210
|
@scanner.skip(regexp(type)) if type
|
198
211
|
|
199
|
-
find_closing_tag(@scanner,
|
212
|
+
find_closing_tag(@scanner, current_ctag_regex)
|
200
213
|
|
201
214
|
# If this tag was the only non-whitespace content on this line, strip
|
202
215
|
# the remaining whitespace. If not, but we've been hanging on to padding
|
@@ -218,7 +231,7 @@ EOF
|
|
218
231
|
|
219
232
|
# Try to find static text, e.g. raw HTML with no {{mustaches}}.
|
220
233
|
def scan_text
|
221
|
-
text = scan_until_exclusive
|
234
|
+
text = scan_until_exclusive @otag_not_regex
|
222
235
|
|
223
236
|
if text.nil?
|
224
237
|
# Couldn't find any otag, which means the rest is just static text.
|
@@ -263,7 +276,7 @@ EOF
|
|
263
276
|
# Used to quickly convert a string into a regular expression
|
264
277
|
# usable by the string scanner.
|
265
278
|
def regexp(thing)
|
266
|
-
|
279
|
+
Regexp.new Regexp.escape(thing) if thing
|
267
280
|
end
|
268
281
|
|
269
282
|
# Raises a SyntaxError. The message should be the name of the
|
@@ -334,7 +347,13 @@ EOF
|
|
334
347
|
|
335
348
|
|
336
349
|
def scan_tag_open_partial content, fetch, padding, pre_match_position
|
337
|
-
@result <<
|
350
|
+
@result << if @option_inline_partials_at_compile_time
|
351
|
+
partial = @partial_resolver.call content
|
352
|
+
partial.gsub!(/^/, padding) unless padding.empty?
|
353
|
+
self.class.new(@options).compile partial
|
354
|
+
else
|
355
|
+
[:mustache, :partial, content, offset, padding]
|
356
|
+
end
|
338
357
|
end
|
339
358
|
alias_method :'scan_tag_<', :scan_tag_open_partial
|
340
359
|
alias_method :'scan_tag_>', :scan_tag_open_partial
|
data/lib/mustache/template.rb
CHANGED
@@ -18,9 +18,10 @@ class Mustache
|
|
18
18
|
attr_reader :source
|
19
19
|
|
20
20
|
# Expects a Mustache template as a string along with a template
|
21
|
-
# path, which it uses to find partials.
|
22
|
-
def initialize(source)
|
21
|
+
# path, which it uses to find partials. Options may be passed.
|
22
|
+
def initialize(source, options = {})
|
23
23
|
@source = source
|
24
|
+
@options = options
|
24
25
|
end
|
25
26
|
|
26
27
|
# Renders the `@source` Mustache template using the given
|
@@ -46,7 +47,7 @@ class Mustache
|
|
46
47
|
# Does the dirty work of transforming a Mustache template into an
|
47
48
|
# interpolation-friendly Ruby string.
|
48
49
|
def compile(src = @source)
|
49
|
-
Generator.new.compile(tokens(src))
|
50
|
+
Generator.new(@options).compile(tokens(src))
|
50
51
|
end
|
51
52
|
alias_method :to_s, :compile
|
52
53
|
|
@@ -55,7 +56,7 @@ class Mustache
|
|
55
56
|
# @return [Array] Array of tokens.
|
56
57
|
#
|
57
58
|
def tokens(src = @source)
|
58
|
-
Parser.new.compile(src)
|
59
|
+
Parser.new(@options).compile(src)
|
59
60
|
end
|
60
61
|
|
61
62
|
# Returns an array of tags.
|
data/lib/mustache/version.rb
CHANGED
data/man/mustache.1
CHANGED
@@ -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" "
|
4
|
+
.TH "MUSTACHE" "1" "November 2016" "DEFUNKT" "Mustache Manual"
|
5
5
|
.
|
6
6
|
.SH "NAME"
|
7
7
|
\fBmustache\fR \- Mustache processor
|
@@ -75,7 +75,7 @@ $ cat template\.mustache
|
|
75
75
|
Hi {{name}}!
|
76
76
|
{{/names}}
|
77
77
|
|
78
|
-
$
|
78
|
+
$ mustache data\.yml template\.mustache
|
79
79
|
Hi chris!
|
80
80
|
Hi mark!
|
81
81
|
Hi scott!
|
@@ -106,7 +106,7 @@ name: scott
|
|
106
106
|
$ cat template\.mustache
|
107
107
|
Hi {{name}}!
|
108
108
|
|
109
|
-
$
|
109
|
+
$ mustache data\.yml template\.mustache
|
110
110
|
Hi chris!
|
111
111
|
Hi mark!
|
112
112
|
Hi scott!
|
data/man/mustache.1.html
CHANGED
@@ -123,7 +123,7 @@ $ cat template.mustache
|
|
123
123
|
Hi {{name}}!
|
124
124
|
{{/names}}
|
125
125
|
|
126
|
-
$
|
126
|
+
$ mustache data.yml template.mustache
|
127
127
|
Hi chris!
|
128
128
|
Hi mark!
|
129
129
|
Hi scott!
|
@@ -146,7 +146,7 @@ name: scott
|
|
146
146
|
$ cat template.mustache
|
147
147
|
Hi {{name}}!
|
148
148
|
|
149
|
-
$
|
149
|
+
$ mustache data.yml template.mustache
|
150
150
|
Hi chris!
|
151
151
|
Hi mark!
|
152
152
|
Hi scott!
|
@@ -204,7 +204,7 @@ data
|
|
204
204
|
|
205
205
|
<ol class='man-decor man-foot man foot'>
|
206
206
|
<li class='tl'>DEFUNKT</li>
|
207
|
-
<li class='tc'>
|
207
|
+
<li class='tc'>November 2016</li>
|
208
208
|
<li class='tr'>mustache(1)</li>
|
209
209
|
</ol>
|
210
210
|
|
data/man/mustache.1.ron
CHANGED
@@ -48,7 +48,7 @@ Now let's combine them.
|
|
48
48
|
Hi {{name}}!
|
49
49
|
{{/names}}
|
50
50
|
|
51
|
-
$
|
51
|
+
$ mustache data.yml template.mustache
|
52
52
|
Hi chris!
|
53
53
|
Hi mark!
|
54
54
|
Hi scott!
|
@@ -70,7 +70,7 @@ For example:
|
|
70
70
|
$ cat template.mustache
|
71
71
|
Hi {{name}}!
|
72
72
|
|
73
|
-
$
|
73
|
+
$ mustache data.yml template.mustache
|
74
74
|
Hi chris!
|
75
75
|
Hi mark!
|
76
76
|
Hi scott!
|
data/man/mustache.5
CHANGED
@@ -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" "
|
4
|
+
.TH "MUSTACHE" "5" "November 2016" "DEFUNKT" "Mustache Manual"
|
5
5
|
.
|
6
6
|
.SH "NAME"
|
7
7
|
\fBmustache\fR \- Logic\-less templates\.
|
data/man/mustache.5.html
CHANGED
data/test/helper.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
require '
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start do
|
3
|
+
add_filter '/test/'
|
4
|
+
end
|
2
5
|
|
3
|
-
require
|
4
|
-
CodeClimate::TestReporter.start
|
6
|
+
require 'minitest/autorun'
|
5
7
|
|
6
8
|
Dir[File.dirname(__FILE__) + '/fixtures/*.rb'].each do |f|
|
7
9
|
require f
|
data/test/mustache_test.rb
CHANGED
@@ -362,7 +362,7 @@ data
|
|
362
362
|
end
|
363
363
|
|
364
364
|
def each *args, &block
|
365
|
-
@people.each
|
365
|
+
@people.each(*args, &block)
|
366
366
|
end
|
367
367
|
end
|
368
368
|
|
@@ -506,6 +506,24 @@ Benvolio is 15
|
|
506
506
|
assert_equal 1, view.calls
|
507
507
|
end
|
508
508
|
|
509
|
+
def test_sections_returning_lambdas_get_called_dynamically_with_text
|
510
|
+
view = Mustache.new
|
511
|
+
view.template = '{{name}}'
|
512
|
+
view[:name] = lambda { '{{dynamic_name}}' }
|
513
|
+
view[:dynamic_name] = 'Chris'
|
514
|
+
|
515
|
+
assert_equal "Chris", view.render.chomp
|
516
|
+
end
|
517
|
+
|
518
|
+
def test_sections_returning_lambdas_get_not_called_dynamically_with_text_if_static
|
519
|
+
view = Mustache.new :static_lambdas => true
|
520
|
+
view.template = '{{name}}'
|
521
|
+
view[:name] = lambda { '{{dynamic_name}}' }
|
522
|
+
view[:dynamic_name] = 'Chris'
|
523
|
+
|
524
|
+
assert_equal "{{dynamic_name}}", view.render.chomp
|
525
|
+
end
|
526
|
+
|
509
527
|
def test_sections_which_refer_to_unary_method_call_them_as_proc
|
510
528
|
kls = Class.new(Mustache) do
|
511
529
|
def unary_method(arg)
|
@@ -706,6 +724,23 @@ text
|
|
706
724
|
end
|
707
725
|
end
|
708
726
|
|
727
|
+
def test_hash_default_proc
|
728
|
+
template = <<template
|
729
|
+
{{greetings.Peter}}
|
730
|
+
{{greetings.Paul}}
|
731
|
+
{{greetings.Mary}}
|
732
|
+
template
|
733
|
+
data = {
|
734
|
+
'greetings' => Hash.new { |hash, key| hash[key] = "Hello, #{key}!" }
|
735
|
+
}
|
736
|
+
|
737
|
+
assert_equal <<expected, Mustache.render(template, data)
|
738
|
+
Hello, Peter!
|
739
|
+
Hello, Paul!
|
740
|
+
Hello, Mary!
|
741
|
+
expected
|
742
|
+
end
|
743
|
+
|
709
744
|
def test_array_of_arrays
|
710
745
|
template = <<template
|
711
746
|
{{#items}}
|
@@ -780,7 +815,17 @@ template
|
|
780
815
|
template = '%%{{title}}%%'
|
781
816
|
|
782
817
|
assert_equal '%%title%%', Mustache.render(template, hashlike)
|
783
|
-
|
784
818
|
end
|
785
819
|
|
820
|
+
def test_instance_with_initialize_render
|
821
|
+
klass = Class.new(Mustache) do
|
822
|
+
def initialize(name)
|
823
|
+
@name = name
|
824
|
+
end
|
825
|
+
attr_reader :name
|
826
|
+
end
|
827
|
+
|
828
|
+
klass.template = "Hi {{name}}!"
|
829
|
+
assert_equal "Hi Dougal!", klass.new("Dougal").render
|
830
|
+
end
|
786
831
|
end
|
data/test/partial_test.rb
CHANGED
@@ -20,6 +20,19 @@ end_partial
|
|
20
20
|
assert_equal "Again, success!", view.render
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_partial_inlining
|
24
|
+
view = Mustache.new :inline_partials_at_compile_time => true
|
25
|
+
view.template = '{{> test/fixtures/inner_partial}}'
|
26
|
+
view[:title] = 'success'
|
27
|
+
|
28
|
+
# Test the rendered result first
|
29
|
+
assert_equal "Again, success!", view.render
|
30
|
+
|
31
|
+
# Now the template should be compiled.
|
32
|
+
# There should be no :partial instruction as the partial has been in-lined.
|
33
|
+
assert_equal false, view.template.tokens.flatten.include?(:partial)
|
34
|
+
end
|
35
|
+
|
23
36
|
def test_view_partial_inherits_context
|
24
37
|
klass = Class.new(TemplatePartial)
|
25
38
|
view = klass.new
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mustache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Wanstrath
|
@@ -11,127 +11,118 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2017-03-26 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
20
|
-
- - ~>
|
20
|
+
- - "~>"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '1.6'
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - ~>
|
27
|
+
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '1.6'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: rake
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
|
-
- - ~>
|
34
|
+
- - "~>"
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: '10.3'
|
37
37
|
type: :development
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- - ~>
|
41
|
+
- - "~>"
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: '10.3'
|
44
44
|
- !ruby/object:Gem::Dependency
|
45
45
|
name: minitest
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
|
-
- - ~>
|
48
|
+
- - "~>"
|
49
49
|
- !ruby/object:Gem::Version
|
50
50
|
version: '5.4'
|
51
51
|
type: :development
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
|
-
- - ~>
|
55
|
+
- - "~>"
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: '5.4'
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: benchmark-ips
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
61
61
|
requirements:
|
62
|
-
- -
|
62
|
+
- - ">="
|
63
63
|
- !ruby/object:Gem::Version
|
64
64
|
version: '0'
|
65
65
|
type: :development
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
|
-
- -
|
69
|
+
- - ">="
|
70
70
|
- !ruby/object:Gem::Version
|
71
71
|
version: '0'
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
73
|
name: ruby-prof
|
74
74
|
requirement: !ruby/object:Gem::Requirement
|
75
75
|
requirements:
|
76
|
-
- -
|
76
|
+
- - ">="
|
77
77
|
- !ruby/object:Gem::Version
|
78
78
|
version: '0'
|
79
79
|
type: :development
|
80
80
|
prerelease: false
|
81
81
|
version_requirements: !ruby/object:Gem::Requirement
|
82
82
|
requirements:
|
83
|
-
- -
|
83
|
+
- - ">="
|
84
84
|
- !ruby/object:Gem::Version
|
85
85
|
version: '0'
|
86
86
|
- !ruby/object:Gem::Dependency
|
87
87
|
name: rdoc
|
88
88
|
requirement: !ruby/object:Gem::Requirement
|
89
89
|
requirements:
|
90
|
-
- - ~>
|
90
|
+
- - "~>"
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: '4.1'
|
93
93
|
type: :development
|
94
94
|
prerelease: false
|
95
95
|
version_requirements: !ruby/object:Gem::Requirement
|
96
96
|
requirements:
|
97
|
-
- - ~>
|
97
|
+
- - "~>"
|
98
98
|
- !ruby/object:Gem::Version
|
99
99
|
version: '4.1'
|
100
100
|
- !ruby/object:Gem::Dependency
|
101
101
|
name: ronn
|
102
102
|
requirement: !ruby/object:Gem::Requirement
|
103
103
|
requirements:
|
104
|
-
- - ~>
|
104
|
+
- - "~>"
|
105
105
|
- !ruby/object:Gem::Version
|
106
106
|
version: '0.7'
|
107
107
|
type: :development
|
108
108
|
prerelease: false
|
109
109
|
version_requirements: !ruby/object:Gem::Requirement
|
110
110
|
requirements:
|
111
|
-
- - ~>
|
111
|
+
- - "~>"
|
112
112
|
- !ruby/object:Gem::Version
|
113
113
|
version: '0.7'
|
114
|
-
description:
|
115
|
-
|
114
|
+
description: |
|
115
|
+
Inspired by ctemplate, Mustache is a framework-agnostic way to render
|
116
116
|
logic-free views.
|
117
117
|
|
118
|
-
|
119
118
|
As ctemplates says, "It emphasizes separating logic from presentation:
|
120
|
-
|
121
119
|
it is impossible to embed application logic in this template
|
122
|
-
|
123
120
|
language.
|
124
121
|
|
125
|
-
|
126
122
|
Think of Mustache as a replacement for your views. Instead of views
|
127
|
-
|
128
123
|
consisting of ERB or HAML with random helpers and arbitrary logic,
|
129
|
-
|
130
124
|
your views are broken into two parts: a Ruby class and an HTML
|
131
|
-
|
132
125
|
template.
|
133
|
-
|
134
|
-
'
|
135
126
|
email: rokusu@gmail.com
|
136
127
|
executables:
|
137
128
|
- mustache
|
@@ -219,17 +210,17 @@ require_paths:
|
|
219
210
|
- lib
|
220
211
|
required_ruby_version: !ruby/object:Gem::Requirement
|
221
212
|
requirements:
|
222
|
-
- -
|
213
|
+
- - ">="
|
223
214
|
- !ruby/object:Gem::Version
|
224
215
|
version: '2.0'
|
225
216
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
226
217
|
requirements:
|
227
|
-
- -
|
218
|
+
- - ">="
|
228
219
|
- !ruby/object:Gem::Version
|
229
220
|
version: '0'
|
230
221
|
requirements: []
|
231
222
|
rubyforge_project:
|
232
|
-
rubygems_version: 2.
|
223
|
+
rubygems_version: 2.6.8
|
233
224
|
signing_key:
|
234
225
|
specification_version: 4
|
235
226
|
summary: Mustache is a framework-agnostic way to render logic-free views.
|