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/lib/mustache.rb CHANGED
@@ -1,6 +1,8 @@
1
+ require 'mustache/enumerable'
1
2
  require 'mustache/template'
2
3
  require 'mustache/context'
3
4
  require 'mustache/settings'
5
+ require 'mustache/utils'
4
6
 
5
7
  # Mustache is the base class from which your Mustache subclasses
6
8
  # should inherit (though it can be used on its own).
@@ -40,7 +42,7 @@ require 'mustache/settings'
40
42
  #
41
43
  # * template_file
42
44
  #
43
- # You can tell Mustache exactly which template to us with this
45
+ # You can tell Mustache exactly which template to use with this
44
46
  # setting. It can be a relative or absolute path.
45
47
  #
46
48
  # * template
@@ -72,48 +74,60 @@ require 'mustache/settings'
72
74
  #
73
75
  class Mustache
74
76
 
77
+ # Initialize a new Mustache instance.
75
78
  #
76
- # Public API
77
- #
79
+ # @param [Hash] options An options hash
80
+ # @option options [String] template_path
81
+ # @option options [String] template_extension
82
+ # @option options [String] template_file
83
+ # @option options [String] template
84
+ # @option options [String] view_namespace
85
+ # @option options [String] view_path
86
+ def initialize(options = {})
87
+ @options = options
88
+
89
+ initialize_settings
90
+ end
78
91
 
79
92
  # Instantiates an instance of this class and calls `render` with
80
93
  # the passed args.
81
94
  #
82
- # Returns a rendered String version of a template
95
+ # @return A rendered String version of a template.
83
96
  def self.render(*args)
84
97
  new.render(*args)
85
98
  end
86
99
 
87
- class << self
88
- alias_method :to_html, :render
89
- alias_method :to_text, :render
90
- end
91
-
92
100
  # Parses our fancy pants template file and returns normal file with
93
101
  # all special {{tags}} and {{#sections}}replaced{{/sections}}.
94
102
  #
95
- # data - A String template or a Hash context. If a Hash is given,
96
- # we'll try to figure out the template from the class.
97
- # ctx - A Hash context if `data` is a String template.
98
- #
99
- # Examples
100
- #
103
+ # @example Render view
101
104
  # @view.render("Hi {{thing}}!", :thing => :world)
102
105
  #
106
+ # @example Set view template and then render
103
107
  # View.template = "Hi {{thing}}!"
104
108
  # @view = View.new
105
109
  # @view.render(:thing => :world)
106
110
  #
107
- # Returns a rendered String version of a template
111
+ # @param [String,Hash] data A String template or a Hash context.
112
+ # If a Hash is given, we'll try to figure
113
+ # out the template from the class.
114
+ # @param [Hash] ctx A Hash context if `data` is a String template.
115
+ # @return [String] Returns a rendered version of a template.
108
116
  def render(data = template, ctx = {})
109
- if data.is_a? Hash
117
+ case data
118
+ when Hash
110
119
  ctx = data
111
- tpl = templateify(template)
112
- elsif data.is_a? Symbol
120
+ when Symbol
113
121
  self.template_name = data
114
- tpl = templateify(template)
122
+ end
123
+
124
+ tpl = case data
125
+ when Hash
126
+ templateify(template)
127
+ when Symbol
128
+ templateify(template)
115
129
  else
116
- tpl = templateify(data)
130
+ templateify(data)
117
131
  end
118
132
 
119
133
  return tpl.render(context) if ctx == {}
@@ -126,15 +140,13 @@ class Mustache
126
140
  end
127
141
  end
128
142
 
129
- alias_method :to_html, :render
130
- alias_method :to_text, :render
131
-
132
143
  # Context accessors.
133
144
  #
134
- # view = Mustache.new
135
- # view[:name] = "Jon"
136
- # view.template = "Hi, {{name}}!"
137
- # view.render # => "Hi, Jon!"
145
+ # @example Context accessors
146
+ # view = Mustache.new
147
+ # view[:name] = "Jon"
148
+ # view.template = "Hi, {{name}}!"
149
+ # view.render # => "Hi, Jon!"
138
150
  def [](key)
139
151
  context[key.to_sym]
140
152
  end
@@ -168,136 +180,144 @@ class Mustache
168
180
  #
169
181
  # Call `render` if you need to process it.
170
182
  def self.partial(name)
171
- File.read("#{template_path}/#{name}.#{template_extension}")
183
+ self.new.partial(name)
172
184
  end
173
185
 
174
186
  # Override this in your subclass if you want to do fun things like
175
187
  # reading templates from a database. It will be rendered by the
176
188
  # context, so all you need to do is return a string.
177
189
  def partial(name)
178
- self.class.partial(name)
190
+ partialpath = template_path.map{|p| "#{p}/#{name}.#{template_extension}" }.find{|pf| File.readable? pf}
191
+
192
+ raise RuntimeError.new("Can't find partial #{name}") if not partialpath and raise_on_context_miss?
193
+
194
+ partialpath ? File.read(partialpath) : ""
179
195
  end
180
196
 
197
+ # Override this to provide custom escaping.
198
+ # By default it uses `CGI.escapeHTML`.
199
+ #
200
+ # @example Overriding #escape
201
+ # class PersonView < Mustache
202
+ # def escape(value)
203
+ # my_html_escape_method(value.to_s)
204
+ # end
205
+ # end
206
+ #
207
+ # @param [Object] value Value to escape.
208
+ # @return [String] Escaped content.
209
+ def escape(value)
210
+ self.escapeHTML(value.to_s)
211
+ end
212
+
181
213
  # Override this to provide custom escaping.
182
214
  #
183
- # class PersonView < Mustache
184
- # def escapeHTML(str)
185
- # my_html_escape_method(str)
215
+ # @example Overriding #escapeHTML
216
+ # class PersonView < Mustache
217
+ # def escapeHTML(str)
218
+ # my_html_escape_method(str)
219
+ # end
186
220
  # end
187
- # end
188
221
  #
189
- # Returns a String
222
+ # @deprecated Use {#escape} instead.
223
+ #
224
+ # Note that {#escape} can receive any kind of object.
225
+ # If your override logic is expecting a string, you will
226
+ # have to call to_s on it yourself.
227
+ # @param [String] str String to escape.
228
+ # @return [String] Escaped HTML.
190
229
  def escapeHTML(str)
191
230
  CGI.escapeHTML(str)
192
231
  end
193
232
 
233
+ # Has this instance or its class already compiled a template?
234
+ def compiled?
235
+ (@template && @template.is_a?(Template)) || self.class.compiled?
236
+ end
237
+
238
+
239
+ private
194
240
 
195
- #
196
- # Private API
197
- #
198
241
 
199
242
  # When given a symbol or string representing a class, will try to produce an
200
243
  # appropriate view class.
201
- # e.g.
244
+ #
245
+ # @example
202
246
  # Mustache.view_namespace = Hurl::Views
203
247
  # Mustache.view_class(:Partial) # => Hurl::Views::Partial
204
248
  def self.view_class(name)
205
- if name != classify(name.to_s)
206
- name = classify(name.to_s)
207
- end
249
+ name = classify(name.to_s)
208
250
 
209
251
  # Emptiness begets emptiness.
210
- if name.to_s == ''
211
- return Mustache
212
- end
252
+ return Mustache if name.to_s.empty?
213
253
 
214
- file_name = underscore(name)
215
254
  name = "#{view_namespace}::#{name}"
255
+ const = rescued_const_get(name)
216
256
 
217
- if const = const_get!(name)
218
- const
219
- elsif File.exists?(file = "#{view_path}/#{file_name}.rb")
220
- require "#{file}".chomp('.rb')
221
- const_get!(name) || Mustache
222
- else
223
- Mustache
224
- end
257
+ return const if const
258
+
259
+ const_from_file(name)
225
260
  end
226
261
 
227
- # Supercharged version of Module#const_get.
228
- #
229
- # Always searches under Object and can find constants by their full name,
230
- # e.g. Mustache::Views::Index
231
- #
232
- # name - The full constant name to find.
233
- #
234
- # Returns the constant if found
235
- # Returns nil if nothing is found
236
- def self.const_get!(name)
237
- name.split('::').inject(Object) do |klass, name|
238
- klass.const_get(name)
239
- end
262
+ def self.rescued_const_get name
263
+ const_get(name, true) || Mustache
240
264
  rescue NameError
241
265
  nil
242
266
  end
243
267
 
268
+ def self.const_from_file name
269
+ file_name = underscore(name)
270
+ file_path = "#{view_path}/#{file_name}.rb"
271
+
272
+ return Mustache unless File.exist?(file_path)
273
+
274
+ require file_path.chomp('.rb')
275
+ rescued_const_get(name)
276
+ end
277
+
244
278
  # Has this template already been compiled? Compilation is somewhat
245
279
  # expensive so it may be useful to check this before attempting it.
246
280
  def self.compiled?
247
281
  @template.is_a? Template
248
282
  end
249
283
 
250
- # Has this instance or its class already compiled a template?
251
- def compiled?
252
- (@template && @template.is_a?(Template)) || self.class.compiled?
253
- end
254
284
 
255
285
  # template_partial => TemplatePartial
256
286
  # template/partial => Template::Partial
257
287
  def self.classify(underscored)
258
- underscored.split('/').map do |namespace|
259
- namespace.split(/[-_]/).map do |part|
260
- part[0] = part[0].chr.upcase; part
261
- end.join
262
- end.join('::')
288
+ Mustache::Utils::String.new(underscored).classify
263
289
  end
264
290
 
265
- # TemplatePartial => template_partial
291
+ # TemplatePartial => template_partial
266
292
  # Template::Partial => template/partial
267
293
  # Takes a string but defaults to using the current class' name.
268
294
  def self.underscore(classified = name)
269
- classified = name if classified.to_s.empty?
270
295
  classified = superclass.name if classified.to_s.empty?
271
296
 
272
- string = classified.dup.split("#{view_namespace}::").last
273
-
274
- string.split('::').map do |part|
275
- part[0] = part[0].chr.downcase
276
- part.gsub(/[A-Z]/) { |s| "_#{s.downcase}"}
277
- end.join('/')
297
+ Mustache::Utils::String.new(classified).underscore(view_namespace)
278
298
  end
279
299
 
280
- # Turns a string into a Mustache::Template. If passed a Template,
281
- # returns it.
282
- def self.templateify(obj)
283
- if obj.is_a?(Template)
284
- obj
285
- else
286
- Template.new(obj.to_s)
287
- end
300
+ # @param [Template,String] obj Turns `obj` into a template
301
+ # @param [Hash] options Options for template creation
302
+ def self.templateify(obj, options = {})
303
+ obj.is_a?(Template) ? obj : Template.new(obj, options)
288
304
  end
289
305
 
290
306
  def templateify(obj)
291
- self.class.templateify(obj)
307
+ opts = {:partial_resolver => self.method(:partial)}
308
+ opts.merge!(@options) if @options.is_a?(Hash)
309
+ self.class.templateify(obj, opts)
292
310
  end
293
311
 
294
312
  # Return the value of the configuration setting on the superclass, or return
295
313
  # the default.
296
314
  #
297
- # attr_name - Symbol name of the attribute. It should match the instance variable.
298
- # default - Default value to use if the superclass does not respond.
315
+ # @param [Symbol] attr_name Name of the attribute. It should match
316
+ # the instance variable.
317
+ # @param [Object] default Default value to use if the superclass does
318
+ # not respond.
299
319
  #
300
- # Returns the inherited or default configuration setting.
320
+ # @return Inherited or default configuration setting.
301
321
  def self.inheritable_config_for(attr_name, default)
302
322
  superclass.respond_to?(attr_name) ? superclass.send(attr_name) : default
303
323
  end
data/man/mustache.1 CHANGED
@@ -1,10 +1,10 @@
1
- .\" generated with Ronn/v0.5
2
- .\" http://github.com/rtomayko/ronn/
1
+ .\" generated with Ronn/v0.7.3
2
+ .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "MUSTACHE" "1" "May 2010" "DEFUNKT" "Mustache Manual"
4
+ .TH "MUSTACHE" "1" "November 2016" "DEFUNKT" "Mustache Manual"
5
5
  .
6
6
  .SH "NAME"
7
- \fBmustache\fR \-\- Mustache processor
7
+ \fBmustache\fR \- Mustache processor
8
8
  .
9
9
  .SH "SYNOPSIS"
10
10
  .
@@ -17,17 +17,13 @@ mustache \-\-tokens <FILE>
17
17
  .fi
18
18
  .
19
19
  .SH "DESCRIPTION"
20
- Mustache is a logic\-less templating system for HTML, config files,
21
- anything.
20
+ Mustache is a logic\-less templating system for HTML, config files, anything\.
22
21
  .
23
22
  .P
24
- The \fBmustache\fR command processes a Mustache template preceded by YAML
25
- frontmatter from standard input and prints one or more documents to
26
- standard output.
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\.
27
24
  .
28
25
  .P
29
- YAML frontmatter beings with \fB\-\-\-\fR on a single line, followed by YAML,
30
- 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\.
31
27
  .
32
28
  .IP "" 4
33
29
  .
@@ -42,12 +38,10 @@ names: [ {name: chris}, {name: mark}, {name: scott} ]
42
38
  .IP "" 0
43
39
  .
44
40
  .P
45
- If you are unfamiliar with YAML, it is a superset of JSON. Valid JSON
46
- should work fine.
41
+ If you are unfamiliar with YAML, it is a superset of JSON\. Valid JSON should work fine\.
47
42
  .
48
43
  .P
49
- After the frontmatter should come any valid Mustache template. See
50
- mustache(5) for an overview of Mustache templates.
44
+ After the frontmatter should come any valid Mustache template\. See mustache(5) for an overview of Mustache templates\.
51
45
  .
52
46
  .P
53
47
  For example:
@@ -65,23 +59,23 @@ For example:
65
59
  .IP "" 0
66
60
  .
67
61
  .P
68
- Now let's combine them.
62
+ Now let\'s combine them\.
69
63
  .
70
64
  .IP "" 4
71
65
  .
72
66
  .nf
73
67
 
74
- $ cat data.yml
68
+ $ cat data\.yml
75
69
  \-\-\-
76
70
  names: [ {name: chris}, {name: mark}, {name: scott} ]
77
71
  \-\-\-
78
72
 
79
- $ cat template.mustache
73
+ $ cat template\.mustache
80
74
  {{#names}}
81
75
  Hi {{name}}!
82
76
  {{/names}}
83
77
 
84
- $ cat data.yml template.mustache | mustache
78
+ $ mustache data\.yml template\.mustache
85
79
  Hi chris!
86
80
  Hi mark!
87
81
  Hi scott!
@@ -91,8 +85,7 @@ Hi scott!
91
85
  .IP "" 0
92
86
  .
93
87
  .P
94
- If you provide multiple YAML documents (as delimited by \fB\-\-\-\fR), your
95
- template will be rendered multiple times. Like a mail merge.
88
+ If you provide multiple YAML documents (as delimited by \fB\-\-\-\fR), your template will be rendered multiple times\. Like a mail merge\.
96
89
  .
97
90
  .P
98
91
  For example:
@@ -101,7 +94,7 @@ For example:
101
94
  .
102
95
  .nf
103
96
 
104
- $ cat data.yml
97
+ $ cat data\.yml
105
98
  \-\-\-
106
99
  name: chris
107
100
  \-\-\-
@@ -110,10 +103,10 @@ name: mark
110
103
  name: scott
111
104
  \-\-\-
112
105
 
113
- $ cat template.mustache
106
+ $ cat template\.mustache
114
107
  Hi {{name}}!
115
108
 
116
- $ cat data.yml template.mustache | mustache
109
+ $ mustache data\.yml template\.mustache
117
110
  Hi chris!
118
111
  Hi mark!
119
112
  Hi scott!
@@ -123,23 +116,15 @@ Hi scott!
123
116
  .IP "" 0
124
117
  .
125
118
  .SH "OPTIONS"
126
- By default \fBmustache\fR will try to render a Mustache template using the
127
- YAML frontmatter you provide. It can do a few other things, however.
119
+ By default \fBmustache\fR will try to render a Mustache template using the YAML frontmatter you provide\. It can do a few other things, however\.
128
120
  .
129
121
  .TP
130
122
  \fB\-c\fR, \fB\-\-compile\fR
131
- Print the compiled Ruby version of a given template. This is the
132
- code that is actually used when rendering a template into a
133
- string. Useful for debugging but only if you are familiar with
134
- Mustache's internals.
123
+ Print the compiled Ruby version of a given template\. This is the code that is actually used when rendering a template into a string\. Useful for debugging but only if you are familiar with Mustache\'s internals\.
135
124
  .
136
125
  .TP
137
126
  \fB\-t\fR, \fB\-\-tokens\fR
138
- Print the tokenized form of a given Mustache template. This can be
139
- used to understand how Mustache parses a template. The tokens are
140
- handed to a generator which compiles them into a Ruby
141
- string. Syntax errors and confused tags, therefor, can probably be
142
- 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\.
143
128
  .
144
129
  .SH "INSTALLATION"
145
130
  If you have RubyGems installed:
@@ -158,10 +143,10 @@ gem install mustache
158
143
  .
159
144
  .nf
160
145
 
161
- $ mustache data.yml template.mustache
162
- $ cat data.yml | mustache \- template.mustache
163
- $ mustache \-c template.mustache
164
- $ cat <<data | ruby mustache \- template.mustache
146
+ $ mustache data\.yml template\.mustache
147
+ $ cat data\.yml | mustache \- template\.mustache
148
+ $ mustache \-c template\.mustache
149
+ $ cat <<data | ruby mustache \- template\.mustache
165
150
  \-\-\-
166
151
  name: Bob
167
152
  age: 30
@@ -177,4 +162,4 @@ Mustache is Copyright (C) 2009 Chris Wanstrath
177
162
  Original CTemplate by Google
178
163
  .
179
164
  .SH "SEE ALSO"
180
- mustache(5), mustache(7), gem(1), \fIhttp://mustache.github.com/\fR
165
+ mustache(5), gem(1), \fIhttp://mustache\.github\.io/\fR