mustache 0.99.5 → 0.99.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -23
- data/Rakefile +1 -1
- data/bin/mustache +30 -12
- data/lib/mustache.rb +4 -11
- data/lib/mustache/blah.rb +116 -0
- data/lib/mustache/context.rb +28 -15
- data/lib/mustache/enumerable.rb +3 -0
- data/lib/mustache/generator.rb +16 -11
- data/lib/mustache/parser.rb +83 -33
- data/lib/mustache/sinatra.rb +1 -1
- data/lib/mustache/template.rb +52 -0
- data/lib/mustache/version.rb +1 -1
- data/man/mustache.1 +4 -4
- data/man/mustache.1.html +6 -6
- data/man/mustache.1.ron +3 -3
- data/man/mustache.5 +8 -8
- data/man/mustache.5.html +11 -9
- data/man/mustache.5.ron +9 -7
- data/test/fixtures/liberal.mustache +1 -0
- data/test/fixtures/liberal.rb +22 -0
- data/test/fixtures/simply_complicated.mustache +25 -0
- data/test/mustache_test.rb +67 -2
- data/test/parser_test.rb +15 -0
- data/test/partial_test.rb +1 -1
- data/test/spec_test.rb +6 -2
- data/test/template_test.rb +33 -0
- metadata +87 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3c1091a71418634c3e493d6b3aae1e5a8f0d0f0
|
4
|
+
data.tar.gz: 87936c1b015243222b2c95c29693106a9ea646a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a422377f6020f923eac84ca194e46b78d05ad611428faa4dede440c090c61e2a30d5d15618286ae72b8ebf486e9aae4b351fee521f5bdc4e13ecc99d1a1677e4
|
7
|
+
data.tar.gz: 30d05bc44030071c322a18ff64235c7bd8da19b03c1cbb4bc68dd3deba33c21d82af75dc435aa2c9845705ea8c7989130aa7626aced0ffb119d6bc18344fa420
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@ As ctemplates says, "It emphasizes separating logic from presentation:
|
|
8
8
|
it is impossible to embed application logic in this template language."
|
9
9
|
|
10
10
|
For a list of implementations (other than Ruby) and tips, see
|
11
|
-
<http://mustache.github.
|
11
|
+
<http://mustache.github.io/>.
|
12
12
|
|
13
13
|
|
14
14
|
Overview
|
@@ -99,16 +99,16 @@ Tag Types
|
|
99
99
|
|
100
100
|
For a language-agnostic overview of Mustache's template syntax, see
|
101
101
|
the `mustache(5)` manpage or
|
102
|
-
<http://mustache.github.
|
102
|
+
<http://mustache.github.io/mustache.5.html>.
|
103
103
|
|
104
104
|
|
105
105
|
Escaping
|
106
106
|
--------
|
107
107
|
|
108
108
|
Mustache does escape all values when using the standard double
|
109
|
-
Mustache syntax. Characters which will be escaped: `& \ " <
|
110
|
-
disable escaping, simply use triple
|
111
|
-
`{{{unescaped_variable}}}`.
|
109
|
+
Mustache syntax. Characters which will be escaped: `& \ " < >` (as
|
110
|
+
well as `'` in Ruby `>= 2.0`). To disable escaping, simply use triple
|
111
|
+
mustaches like `{{{unescaped_variable}}}`.
|
112
112
|
|
113
113
|
Example: Using `{{variable}}` inside a template for `5 > 2` will
|
114
114
|
result in `5 > 2`, where as the usage of `{{{variable}}}` will
|
@@ -283,16 +283,16 @@ Sinatra
|
|
283
283
|
|
284
284
|
Mustache ships with Sinatra integration. Please see
|
285
285
|
`lib/mustache/sinatra.rb` or
|
286
|
-
<
|
286
|
+
<https://github.com/defunkt/mustache/blob/master/lib/mustache/sinatra.rb>
|
287
287
|
for complete documentation.
|
288
288
|
|
289
289
|
An example Sinatra application is also provided:
|
290
|
-
<
|
290
|
+
<https://github.com/defunkt/mustache-sinatra-example>
|
291
291
|
|
292
292
|
If you are upgrading to Sinatra 1.0 and Mustache 0.9.0+ from Mustache
|
293
293
|
0.7.0 or lower, the settings have changed. But not that much.
|
294
294
|
|
295
|
-
See [this diff](
|
295
|
+
See [this diff](https://gist.github.com/defunkt/345490) for what you need to
|
296
296
|
do. Basically, things are named properly now and all should be
|
297
297
|
contained in a hash set using `set :mustache, hash`.
|
298
298
|
|
@@ -317,11 +317,7 @@ Using Rails? Add this to your initializer or environment file:
|
|
317
317
|
Vim
|
318
318
|
---
|
319
319
|
|
320
|
-
|
321
|
-
is included under the contrib/ directory.
|
322
|
-
|
323
|
-
See <http://gist.github.com/323622> for installation instructions.
|
324
|
-
|
320
|
+
vim-mustache-handlebars is available at https://github.com/mustache/vim-mustache-handlebars
|
325
321
|
|
326
322
|
Emacs
|
327
323
|
-----
|
@@ -332,16 +328,16 @@ mustache-mode.el is available at https://github.com/mustache/emacs
|
|
332
328
|
TextMate
|
333
329
|
--------
|
334
330
|
|
335
|
-
[Mustache.tmbundle](
|
331
|
+
[Mustache.tmbundle](https://github.com/defunkt/Mustache.tmbundle)
|
336
332
|
|
337
|
-
See <
|
333
|
+
See <https://gist.github.com/defunkt/323624> for installation instructions.
|
338
334
|
|
339
335
|
|
340
336
|
Command Line
|
341
337
|
------------
|
342
338
|
|
343
339
|
See `mustache(1)` man page or
|
344
|
-
<http://mustache.github.
|
340
|
+
<http://mustache.github.io/mustache.1.html>
|
345
341
|
for command line docs.
|
346
342
|
|
347
343
|
|
@@ -356,8 +352,8 @@ Installation
|
|
356
352
|
Acknowledgements
|
357
353
|
----------------
|
358
354
|
|
359
|
-
Thanks to [Tom Preston-Werner](
|
360
|
-
me ctemplate and [Leah Culver](
|
355
|
+
Thanks to [Tom Preston-Werner](https://github.com/mojombo) for showing
|
356
|
+
me ctemplate and [Leah Culver](https://github.com/leah) for the name "Mustache."
|
361
357
|
|
362
358
|
Special thanks to [Magnus Holm](http://judofyr.net/) for all his
|
363
359
|
awesome work on Mustache's parser.
|
@@ -391,9 +387,9 @@ The archive can be found at <http://librelist.com/browser/>.
|
|
391
387
|
Meta
|
392
388
|
----
|
393
389
|
|
394
|
-
* Code: `git clone
|
395
|
-
* Home: <http://mustache.github.
|
396
|
-
* Bugs: <
|
390
|
+
* Code: `git clone https://github.com/defunkt/mustache.git`
|
391
|
+
* Home: <http://mustache.github.io>
|
392
|
+
* Bugs: <https://github.com/defunkt/mustache/issues>
|
397
393
|
* List: <mustache@librelist.com>
|
398
394
|
* Gems: <http://rubygems.org/gems/mustache>
|
399
395
|
|
@@ -402,8 +398,8 @@ You can also find us in `#{` on irc.freenode.net.
|
|
402
398
|
[1]: http://code.google.com/p/google-ctemplate/
|
403
399
|
[2]: http://www.ivan.fomichev.name/2008/05/erlang-template-engine-prototype.html
|
404
400
|
[3]: http://google-ctemplate.googlecode.com/svn/trunk/doc/howto.html
|
405
|
-
[4]:
|
401
|
+
[4]: https://github.com/brynary/rack-bug/
|
406
402
|
[5]: http://img.skitch.com/20091027-n8pxwwx8r61tc318a15q1n6m14.png
|
407
403
|
[cb]: http://wiki.github.com/defunkt/resque/contributing
|
408
404
|
[fk]: http://help.github.com/forking/
|
409
|
-
[is]:
|
405
|
+
[is]: https://github.com/defunkt/mustache/issues
|
data/Rakefile
CHANGED
data/bin/mustache
CHANGED
@@ -64,20 +64,38 @@ class Mustache
|
|
64
64
|
opts.parse!(args)
|
65
65
|
end
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
doc = input_stream.read
|
67
|
+
def self.yaml_is_array?(yaml)
|
68
|
+
yaml.is_a? Array and yaml.length == 1 and yaml[0].is_a? Array
|
69
|
+
end
|
71
70
|
|
72
|
-
|
73
|
-
yaml
|
74
|
-
|
71
|
+
def self.yaml_is_object?(yaml)
|
72
|
+
yaml.is_a? Array and yaml.length == 1 and yaml[0].is_a? Hash
|
73
|
+
end
|
75
74
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
# Does the dirty work of reading files from the command line then
|
76
|
+
# processing them. The meat of this script, if you will.
|
77
|
+
def self.process_files(input_files)
|
78
|
+
doc = input_files.file.read
|
79
|
+
|
80
|
+
yaml = nil
|
81
|
+
begin
|
82
|
+
yaml = RUBY_VERSION >= '1.9.3' ? YAML.load_stream(doc) : YAML.each_document(doc)
|
83
|
+
rescue
|
84
|
+
puts "Unable to parse yaml!"
|
85
|
+
end
|
86
|
+
|
87
|
+
if yaml.nil?
|
80
88
|
puts Mustache.render(doc)
|
89
|
+
else
|
90
|
+
template = input_files.skip.file.read
|
91
|
+
|
92
|
+
if self.yaml_is_array?(yaml)
|
93
|
+
puts Mustache.render(template, yaml[0].reduce({}) {|hash, currentHash| hash.merge(currentHash)})
|
94
|
+
elsif self.yaml_is_object?(yaml)
|
95
|
+
puts Mustache.render(template, yaml[0])
|
96
|
+
else
|
97
|
+
puts Mustache.render(template, yaml)
|
98
|
+
end
|
81
99
|
end
|
82
100
|
end
|
83
101
|
end
|
@@ -89,6 +107,6 @@ ARGV << '-h' if ARGV.empty? && $stdin.tty?
|
|
89
107
|
# Process options
|
90
108
|
Mustache::CLI.parse_options(ARGV) if $stdin.tty?
|
91
109
|
|
92
|
-
# Still here - process ARGF
|
110
|
+
# Still here - process rest of ARGF
|
93
111
|
Mustache::CLI.process_files(ARGF)
|
94
112
|
|
data/lib/mustache.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'mustache/enumerable'
|
1
2
|
require 'mustache/template'
|
2
3
|
require 'mustache/context'
|
3
4
|
require 'mustache/settings'
|
@@ -202,14 +203,10 @@ class Mustache
|
|
202
203
|
# Mustache.view_namespace = Hurl::Views
|
203
204
|
# Mustache.view_class(:Partial) # => Hurl::Views::Partial
|
204
205
|
def self.view_class(name)
|
205
|
-
|
206
|
-
name = classify(name.to_s)
|
207
|
-
end
|
206
|
+
name = classify(name.to_s)
|
208
207
|
|
209
208
|
# Emptiness begets emptiness.
|
210
|
-
if name.to_s == ''
|
211
|
-
return Mustache
|
212
|
-
end
|
209
|
+
return Mustache if name.to_s == ''
|
213
210
|
|
214
211
|
file_name = underscore(name)
|
215
212
|
name = "#{view_namespace}::#{name}"
|
@@ -280,11 +277,7 @@ class Mustache
|
|
280
277
|
# Turns a string into a Mustache::Template. If passed a Template,
|
281
278
|
# returns it.
|
282
279
|
def self.templateify(obj)
|
283
|
-
|
284
|
-
obj
|
285
|
-
else
|
286
|
-
Template.new(obj.to_s)
|
287
|
-
end
|
280
|
+
obj.is_a?(Template) ? obj : Template.new(obj.to_s)
|
288
281
|
end
|
289
282
|
|
290
283
|
def templateify(obj)
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
|
3
|
+
class Mustache::Template
|
4
|
+
def token_names
|
5
|
+
def recursor(toks, section)
|
6
|
+
toks.map do |token|
|
7
|
+
next unless token.is_a? Array
|
8
|
+
if token[0] == :mustache && [:etag,:utag].include? token[1]
|
9
|
+
(section + [token[2][2][0]]).join '.'
|
10
|
+
elsif token[0] == :mustache && [:section,:inverted_section].include? token[1]
|
11
|
+
recursor(token[4], section + [token[2][2][0]])
|
12
|
+
else
|
13
|
+
recursor(token, section)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
recursor(tokens, []).flatten.reject(&:nil?).uniq
|
18
|
+
end
|
19
|
+
|
20
|
+
def section_names
|
21
|
+
def recursor(toks, section)
|
22
|
+
sections = []
|
23
|
+
toks.each do |token|
|
24
|
+
next unless token.is_a? Array
|
25
|
+
if token[0] == :mustache && [:section,:inverted_section].include? token[1]
|
26
|
+
new_section = section + [token[2][2][0]]
|
27
|
+
sections += [ new_section.join('.') ] + recursor(token[4], new_section)
|
28
|
+
else
|
29
|
+
sections += recursor(token, section)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
sections
|
33
|
+
end
|
34
|
+
recursor(tokens,[]).reject(&:nil?).uniq
|
35
|
+
end
|
36
|
+
|
37
|
+
def partial_names
|
38
|
+
def recursor(toks)
|
39
|
+
partials = []
|
40
|
+
toks.each do |token|
|
41
|
+
next unless token.is_a? Array
|
42
|
+
partials += if token[0..1] == [:mustache, :partial]
|
43
|
+
[token[2]] # partial here
|
44
|
+
else
|
45
|
+
recursor(token)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
partials
|
49
|
+
end
|
50
|
+
recursor(tokens).reject(&:nil?).uniq
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
if __FILE__ == $0
|
56
|
+
require "test/unit"
|
57
|
+
|
58
|
+
class TestMustacheTokenNames < Test::Unit::TestCase
|
59
|
+
|
60
|
+
def setup
|
61
|
+
@template = Mustache::Template.new(@@template_text ||= DATA.read)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_token_names
|
65
|
+
assert_equal(@template.token_names,
|
66
|
+
[ "yourname",
|
67
|
+
"HOME",
|
68
|
+
"friend.name",
|
69
|
+
"friend.morr.word",
|
70
|
+
"friend.morr.up",
|
71
|
+
"friend.morr.awesomesauce",
|
72
|
+
"friend.morr.hiss",
|
73
|
+
"friend.notinmorr",
|
74
|
+
"friend.person",
|
75
|
+
"love",
|
76
|
+
"triplestash"
|
77
|
+
]
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_partial_names
|
82
|
+
assert_equal(@template.partial_names, ["partial1", "partial2"])
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_section_names
|
86
|
+
assert_equal(@template.section_names, ["friend", "friend.morr"])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
__END__
|
92
|
+
Hi there {{yourname}}. Your home directory is {{HOME}}.
|
93
|
+
|
94
|
+
{{#friend}}
|
95
|
+
Your friend is named {{name}}
|
96
|
+
{{#morr}}
|
97
|
+
Hey {{word}} {{up}} {{{awesomesauce}}}.
|
98
|
+
{{/morr}}
|
99
|
+
{{^morr}}
|
100
|
+
Booooo. {{hiss}}
|
101
|
+
{{/morr}}
|
102
|
+
{{notinmorr}}
|
103
|
+
{{> partial1}}
|
104
|
+
{{/friend}}
|
105
|
+
{{^friend}}
|
106
|
+
You have no friends, {{person}}. You suck.
|
107
|
+
{{/friend}}
|
108
|
+
|
109
|
+
{{> partial2}}
|
110
|
+
{{! comments are awesome }}
|
111
|
+
|
112
|
+
{{={% %}=}}
|
113
|
+
|
114
|
+
{%love%}
|
115
|
+
{%={{ }}=%}
|
116
|
+
{{{triplestash}}}
|
data/lib/mustache/context.rb
CHANGED
@@ -31,7 +31,7 @@ class Mustache
|
|
31
31
|
part = mustache.partial(name).to_s.gsub(/^/, indentation)
|
32
32
|
|
33
33
|
# Call the Mustache's `partial` method and render the result.
|
34
|
-
|
34
|
+
mustache.render(part, self)
|
35
35
|
end
|
36
36
|
|
37
37
|
# Find the first Mustache in the stack. If we're being rendered
|
@@ -80,7 +80,7 @@ class Mustache
|
|
80
80
|
# Do we know about a particular key? In other words, will calling
|
81
81
|
# `context[key]` give us a result that was set. Basically.
|
82
82
|
def has_key?(key)
|
83
|
-
!!fetch(key)
|
83
|
+
!!fetch(key, false)
|
84
84
|
rescue ContextMiss
|
85
85
|
false
|
86
86
|
end
|
@@ -97,9 +97,7 @@ class Mustache
|
|
97
97
|
next if frame == self
|
98
98
|
|
99
99
|
value = find(frame, name, :__missing)
|
100
|
-
if value != :__missing
|
101
|
-
return value
|
102
|
-
end
|
100
|
+
return value if value != :__missing
|
103
101
|
end
|
104
102
|
|
105
103
|
if default == :__raise || mustache_in_stack.raise_on_context_miss?
|
@@ -121,22 +119,37 @@ class Mustache
|
|
121
119
|
#
|
122
120
|
# Returns the value of key in obj if it is found and default otherwise.
|
123
121
|
def find(obj, key, default = nil)
|
124
|
-
hash = obj.respond_to?(:
|
122
|
+
hash = obj.respond_to?(:to_hash)
|
123
|
+
|
124
|
+
if !hash
|
125
|
+
# If a class, we need to find tags (methods) per Parser::ALLOWED_CONTENT.
|
126
|
+
if key.to_s.include?('-')
|
127
|
+
key = key.to_s.gsub('-', '_')
|
128
|
+
end
|
125
129
|
|
126
|
-
|
130
|
+
if obj.respond_to?(key)
|
131
|
+
meth = obj.method(key) rescue proc { obj.send(key) }
|
132
|
+
if meth.arity == 1
|
133
|
+
meth.to_proc
|
134
|
+
else
|
135
|
+
meth[]
|
136
|
+
end
|
137
|
+
else
|
138
|
+
default
|
139
|
+
end
|
140
|
+
elsif hash && obj.has_key?(key)
|
127
141
|
obj[key]
|
128
142
|
elsif hash && obj.has_key?(key.to_s)
|
129
143
|
obj[key.to_s]
|
130
|
-
elsif !hash && obj.respond_to?(key)
|
131
|
-
meth = obj.method(key) rescue proc { obj.send(key) }
|
132
|
-
if meth.arity == 1
|
133
|
-
meth.to_proc
|
134
|
-
else
|
135
|
-
meth[]
|
136
|
-
end
|
137
144
|
else
|
138
|
-
default
|
145
|
+
obj[key] || default
|
139
146
|
end
|
140
147
|
end
|
141
148
|
end
|
142
149
|
end
|
150
|
+
|
151
|
+
class Hash
|
152
|
+
def to_hash
|
153
|
+
self
|
154
|
+
end unless method_defined?(:to_hash)
|
155
|
+
end
|
data/lib/mustache/generator.rb
CHANGED
@@ -64,17 +64,22 @@ class Mustache
|
|
64
64
|
#
|
65
65
|
# [:multi,
|
66
66
|
# [:static, "Hello "],
|
67
|
-
# [:mustache, :etag,
|
67
|
+
# [:mustache, :etag,
|
68
|
+
# [:mustache, :fetch, ["name"]]],
|
68
69
|
# [:static, "\nYou have just won $"],
|
69
|
-
#
|
70
|
-
# [:
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
70
|
+
# [:mustache, :etag,
|
71
|
+
# [:mustache, :fetch, ["value"]]],
|
72
|
+
# [:static, "!\n"],
|
73
|
+
# [:mustache,
|
74
|
+
# :section,
|
75
|
+
# [:mustache, :fetch, ["in_ca"]],
|
76
|
+
# [:multi,
|
77
|
+
# [:static, "Well, $"],
|
78
|
+
# [:mustache, :etag,
|
79
|
+
# [:mustache, :fetch, ["taxed_value"]]],
|
80
|
+
# [:static, ", after taxes.\n"]],
|
81
|
+
# "Well, ${{taxed_value}}, after taxes.\n",
|
82
|
+
# ["{{", "}}"]]]
|
78
83
|
def compile!(exp)
|
79
84
|
case exp.first
|
80
85
|
when :multi
|
@@ -111,7 +116,7 @@ class Mustache
|
|
111
116
|
t.render(ctx.dup)
|
112
117
|
else
|
113
118
|
# Shortcut when passed non-array
|
114
|
-
v = [v] unless v.is_a?(Array) || defined?(Enumerator) && v.is_a?(Enumerator)
|
119
|
+
v = [v] unless v.is_a?(Array) || v.is_a?(Mustache::Enumerable) || defined?(Enumerator) && v.is_a?(Enumerator)
|
115
120
|
|
116
121
|
v.map { |h| ctx.push(h); r = #{code}; ctx.pop; r }.join
|
117
122
|
end
|