mustache 0.3.2 → 0.4.0
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.
- data/HISTORY.md +16 -0
- data/README.md +37 -7
- data/examples/{comments.html → comments.mustache} +0 -0
- data/examples/{complex_view.html → complex_view.mustache} +0 -0
- data/examples/{delimiters.html → delimiters.mustache} +0 -0
- data/examples/{double_section.html → double_section.mustache} +0 -0
- data/examples/{escaped.html → escaped.mustache} +0 -0
- data/examples/{inner_partial.html → inner_partial.mustache} +0 -0
- data/examples/namespaced.mustache +1 -0
- data/examples/namespaced.rb +17 -0
- data/examples/{simple.html → simple.mustache} +0 -0
- data/examples/{template_partial.html → template_partial.mustache} +0 -0
- data/examples/{unescaped.html → unescaped.mustache} +0 -0
- data/examples/{view_partial.html → view_partial.mustache} +0 -0
- data/lib/mustache.rb +94 -6
- data/lib/mustache/context.rb +13 -1
- data/lib/mustache/sinatra.rb +9 -29
- data/lib/mustache/template.rb +27 -2
- data/lib/mustache/version.rb +1 -1
- data/lib/rack/bug/panels/mustache_panel.rb +81 -0
- data/lib/rack/bug/panels/mustache_panel/mustache_extension.rb +25 -0
- data/lib/rack/bug/panels/mustache_panel/view.mustache +32 -0
- data/test/autoloading_test.rb +38 -0
- data/test/mustache_test.rb +49 -1
- metadata +20 -12
data/HISTORY.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
## 0.4.0 (2009-10-27)
|
2
|
+
|
3
|
+
* Stopped raising context miss exceptions by default
|
4
|
+
* Added `Mustache.raise_on_context_miss` setting (defaults to false)
|
5
|
+
* Throw Mustache::ContextMiss when raise_on_context_miss is true and
|
6
|
+
we encounter a miss.
|
7
|
+
* The default template extension is now "mustache" (instead of "html").
|
8
|
+
* Added the `view_namespace` and `view_path` settings to `Mustache`
|
9
|
+
* Added `Mustache.view_class` method which autoloads a class using the
|
10
|
+
new `view_namespace` and `view_path` settings. Should be used by
|
11
|
+
plugin developers.
|
12
|
+
* Updated the Sinatra extension to use the new `view_class` method
|
13
|
+
* Unclosed sections now throw a helpful error message
|
14
|
+
* Report line numbers on unclosed section errors
|
15
|
+
* Added Rack::Bug panel
|
16
|
+
|
1
17
|
## 0.3.2 (2009-10-19)
|
2
18
|
|
3
19
|
* Bugfix: Partials in Sinatra were using the wrong path.
|
data/README.md
CHANGED
@@ -103,9 +103,11 @@ The most basic tag is the variable. A `{{name}}` tag in a basic
|
|
103
103
|
template will try to call the `name` method on your view. If there is
|
104
104
|
no `name` method, an exception will be raised.
|
105
105
|
|
106
|
-
All variables are HTML escaped by default. If you want
|
107
|
-
|
108
|
-
|
106
|
+
All variables are HTML escaped by default. If you want to return
|
107
|
+
unescaped HTML, use the triple mustache: `{{{name}}}`.
|
108
|
+
|
109
|
+
By default a variable "miss" returns an empty string. You can
|
110
|
+
configure this by setting `Mustache.raise_on_context_miss` to true.
|
109
111
|
|
110
112
|
### Boolean Sections
|
111
113
|
|
@@ -215,7 +217,7 @@ ctemplate and friends want you to hand a dictionary to the template
|
|
215
217
|
processor. Mustache supports a similar concept. Feel free to mix the
|
216
218
|
class-based and this more procedural style at your leisure.
|
217
219
|
|
218
|
-
Given this template (winner.
|
220
|
+
Given this template (winner.mustache):
|
219
221
|
|
220
222
|
Hello {{name}}
|
221
223
|
You have just won ${{value}}!
|
@@ -247,7 +249,7 @@ A word on templates. By default, a view will try to find its template
|
|
247
249
|
on disk by searching for an HTML file in the current directory that
|
248
250
|
follows the classic Ruby naming convention.
|
249
251
|
|
250
|
-
TemplatePartial => ./template_partial.
|
252
|
+
TemplatePartial => ./template_partial.mustache
|
251
253
|
|
252
254
|
You can set the search path using `Mustache.template_path`. It can be set on a
|
253
255
|
class by class basis:
|
@@ -257,13 +259,13 @@ class by class basis:
|
|
257
259
|
... etc ...
|
258
260
|
end
|
259
261
|
|
260
|
-
Now `Simple` will look for `simple.
|
262
|
+
Now `Simple` will look for `simple.mustache` in the directory it resides
|
261
263
|
in, no matter the cwd.
|
262
264
|
|
263
265
|
If you want to just change what template is used you can set
|
264
266
|
`Mustache.template_file` directly:
|
265
267
|
|
266
|
-
Simple.template_file = './blah.
|
268
|
+
Simple.template_file = './blah.mustache'
|
267
269
|
|
268
270
|
Mustache also allows you to define the extension it'll use.
|
269
271
|
|
@@ -283,6 +285,15 @@ Or set a different template for a single instance:
|
|
283
285
|
Whatever works.
|
284
286
|
|
285
287
|
|
288
|
+
Views
|
289
|
+
-----
|
290
|
+
|
291
|
+
Mustache supports a bit of magic when it comes to views. If you're
|
292
|
+
authoring a plugin or extension for a web framework (Sinatra, Rails,
|
293
|
+
etc), check out the `view_namespace` and `view_path` settings on the
|
294
|
+
`Mustache` class. They will surely provide needed assistance.
|
295
|
+
|
296
|
+
|
286
297
|
Helpers
|
287
298
|
-------
|
288
299
|
|
@@ -364,6 +375,23 @@ An example Sinatra application is also provided:
|
|
364
375
|
<http://github.com/defunkt/mustache-sinatra-example>
|
365
376
|
|
366
377
|
|
378
|
+
[Rack::Bug][4]
|
379
|
+
---------
|
380
|
+
|
381
|
+
Mustache also ships with a `Rack::Bug` panel. In your `config.ru` add
|
382
|
+
the following code:
|
383
|
+
|
384
|
+
require 'rack/bug/panels/mustache_panel'
|
385
|
+
use Rack::Bug::MustachePanel
|
386
|
+
|
387
|
+
Using Rails? Add this to your initializer or environment file:
|
388
|
+
|
389
|
+
require 'rack/bug/panels/mustache_panel'
|
390
|
+
config.middleware.use "Rack::Bug::MustachePanel"
|
391
|
+
|
392
|
+
[][5]
|
393
|
+
|
394
|
+
|
367
395
|
Vim
|
368
396
|
---
|
369
397
|
|
@@ -405,3 +433,5 @@ Meta
|
|
405
433
|
[1]: http://code.google.com/p/google-ctemplate/
|
406
434
|
[2]: http://www.ivan.fomichev.name/2008/05/erlang-template-engine-prototype.html
|
407
435
|
[3]: http://google-ctemplate.googlecode.com/svn/trunk/doc/howto.html
|
436
|
+
[4]: http://github.com/brynary/rack-bug/
|
437
|
+
[5]: http://img.skitch.com/20091027-n8pxwwx8r61tc318a15q1n6m14.png
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>{{title}}</h1>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
require 'mustache'
|
3
|
+
|
4
|
+
module TestViews
|
5
|
+
class Namespaced < Mustache
|
6
|
+
self.path = File.dirname(__FILE__)
|
7
|
+
|
8
|
+
def title
|
9
|
+
"Dragon < Tiger"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
if $0 == __FILE__
|
16
|
+
puts TestViews::Namespaced.to_html
|
17
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/lib/mustache.rb
CHANGED
@@ -7,7 +7,7 @@ require 'mustache/context'
|
|
7
7
|
# The typical Mustache workflow is as follows:
|
8
8
|
#
|
9
9
|
# * Create a Mustache subclass: class Stats < Mustache
|
10
|
-
# * Create a template: stats.
|
10
|
+
# * Create a template: stats.mustache
|
11
11
|
# * Instantiate an instance: view = Stats.new
|
12
12
|
# * Render that instance: view.render
|
13
13
|
#
|
@@ -30,12 +30,12 @@ require 'mustache/context'
|
|
30
30
|
# looking for a template. By default it is "."
|
31
31
|
# Setting it to /usr/local/templates, for example, means (given all
|
32
32
|
# other settings are default) a Mustache subclass `Stats` will try to
|
33
|
-
# load /usr/local/templates/stats.
|
33
|
+
# load /usr/local/templates/stats.mustache
|
34
34
|
#
|
35
35
|
# * template_extension
|
36
36
|
#
|
37
37
|
# The `template_extension` is the extension Mustache uses when looking
|
38
|
-
# for template files. By default it is "
|
38
|
+
# for template files. By default it is "mustache"
|
39
39
|
#
|
40
40
|
# * template_file
|
41
41
|
#
|
@@ -56,6 +56,19 @@ require 'mustache/context'
|
|
56
56
|
# view.template = "Hi, {{person}}!"
|
57
57
|
# view[:person] = 'Mom'
|
58
58
|
# view.render # => Hi, mom!
|
59
|
+
#
|
60
|
+
# * view_namespace
|
61
|
+
#
|
62
|
+
# To make life easy on those developing Mustache plugins for web frameworks or
|
63
|
+
# other libraries, Mustache will attempt to load view classes (i.e. Mustache
|
64
|
+
# subclasses) using the `view_class` class method. The `view_namespace` tells
|
65
|
+
# Mustache under which constant view classes live. By default it is `Object`.
|
66
|
+
#
|
67
|
+
# * view_path
|
68
|
+
#
|
69
|
+
# Similar to `template_path`, the `view_path` option tells Mustache where to look
|
70
|
+
# for files containing view classes when using the `view_class` method.
|
71
|
+
#
|
59
72
|
class Mustache
|
60
73
|
# Helper method for quickly instantiating and rendering a view.
|
61
74
|
def self.render(*args)
|
@@ -93,9 +106,9 @@ class Mustache
|
|
93
106
|
self.template_path = path
|
94
107
|
end
|
95
108
|
|
96
|
-
# A Mustache template's default extension is '
|
109
|
+
# A Mustache template's default extension is 'mustache'
|
97
110
|
def self.template_extension
|
98
|
-
@template_extension ||= '
|
111
|
+
@template_extension ||= 'mustache'
|
99
112
|
end
|
100
113
|
|
101
114
|
def self.template_extension=(template_extension)
|
@@ -104,7 +117,7 @@ class Mustache
|
|
104
117
|
end
|
105
118
|
|
106
119
|
# The template file is the absolute path of the file Mustache will
|
107
|
-
# use as its template. By default it's ./class_name.
|
120
|
+
# use as its template. By default it's ./class_name.mustache
|
108
121
|
def self.template_file
|
109
122
|
@template_file || "#{path}/#{underscore}.#{template_extension}"
|
110
123
|
end
|
@@ -126,6 +139,75 @@ class Mustache
|
|
126
139
|
@template = templateify(template)
|
127
140
|
end
|
128
141
|
|
142
|
+
# The constant under which Mustache will look for views. By default it's
|
143
|
+
# `Object`, but it might be nice to set it to something like `Hurl::Views` if
|
144
|
+
# your app's main namespace is `Hurl`.
|
145
|
+
def self.view_namespace
|
146
|
+
@view_namespace || Object
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.view_namespace=(namespace)
|
150
|
+
@view_namespace = namespace
|
151
|
+
end
|
152
|
+
|
153
|
+
# Mustache searches the view path for .rb files to require when asked to find a
|
154
|
+
# view class. Defaults to "."
|
155
|
+
def self.view_path
|
156
|
+
@view_path ||= '.'
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.view_path=(path)
|
160
|
+
@view_path = path
|
161
|
+
end
|
162
|
+
|
163
|
+
# When given a symbol or string representing a class, will try to produce an
|
164
|
+
# appropriate view class.
|
165
|
+
# e.g.
|
166
|
+
# Mustache.view_namespace = Hurl::Views
|
167
|
+
# Mustache.view_class(:Partial) # => Hurl::Views::Partial
|
168
|
+
def self.view_class(name)
|
169
|
+
if name != classify(name.to_s)
|
170
|
+
name = classify(name.to_s)
|
171
|
+
end
|
172
|
+
|
173
|
+
# Emptiness begets emptiness.
|
174
|
+
if name.to_s == ''
|
175
|
+
return Mustache
|
176
|
+
end
|
177
|
+
|
178
|
+
file_name = underscore(name)
|
179
|
+
namespace = view_namespace
|
180
|
+
|
181
|
+
if namespace.const_defined?(:Views) && namespace::Views.const_defined?(name)
|
182
|
+
namespace::Views.const_get(name)
|
183
|
+
elsif namespace.const_defined?(name)
|
184
|
+
namespace.const_get(name)
|
185
|
+
elsif File.exists?(file = "#{view_path}/#{file_name}.rb")
|
186
|
+
require "#{file}".chomp('.rb')
|
187
|
+
if namespace.const_defined?(:Views)
|
188
|
+
namespace::Views.const_get(name)
|
189
|
+
else
|
190
|
+
namespace.const_get(name)
|
191
|
+
end
|
192
|
+
else
|
193
|
+
Mustache
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Should an exception be raised when we cannot find a corresponding method
|
198
|
+
# or key in the current context? By default this is false to emulate ctemplate's
|
199
|
+
# behavior, but it may be useful to enable when debugging or developing.
|
200
|
+
#
|
201
|
+
# If set to true and there is a context miss, `Mustache::ContextMiss` will
|
202
|
+
# be raised.
|
203
|
+
def self.raise_on_context_miss?
|
204
|
+
@raise_on_context_miss
|
205
|
+
end
|
206
|
+
|
207
|
+
def self.raise_on_context_miss=(boolean)
|
208
|
+
@raise_on_context_miss = boolean
|
209
|
+
end
|
210
|
+
|
129
211
|
# Has this template already been compiled? Compilation is somewhat
|
130
212
|
# expensive so it may be useful to check this before attempting it.
|
131
213
|
def self.compiled?
|
@@ -178,6 +260,12 @@ class Mustache
|
|
178
260
|
@template = templateify(template)
|
179
261
|
end
|
180
262
|
|
263
|
+
# Instance level version of `Mustache.raise_on_context_miss?`
|
264
|
+
def raise_on_context_miss?
|
265
|
+
self.class.raise_on_context_miss? || @raise_on_context_miss
|
266
|
+
end
|
267
|
+
attr_writer :raise_on_context_miss
|
268
|
+
|
181
269
|
# A helper method which gives access to the context at a given time.
|
182
270
|
# Kind of a hack for now, but useful when you're in an iterating section
|
183
271
|
# and want access to the hash currently being iterated over.
|
data/lib/mustache/context.rb
CHANGED
@@ -1,4 +1,14 @@
|
|
1
1
|
class Mustache
|
2
|
+
# A ContextMiss is raised whenever a tag's target can not be found
|
3
|
+
# in the current context if `Mustache#raise_on_context_miss?` is
|
4
|
+
# set to true.
|
5
|
+
#
|
6
|
+
# For example, if your View class does not respond to `music` but
|
7
|
+
# your template contains a `{{template}}` tag this exception will be raised.
|
8
|
+
#
|
9
|
+
# By default it is not raised. See Mustache.raise_on_context_miss.
|
10
|
+
class ContextMiss < RuntimeError; end
|
11
|
+
|
2
12
|
# A Context represents the context which a Mustache template is
|
3
13
|
# executed within. All Mustache tags reference keys in the Context.
|
4
14
|
class Context < Hash
|
@@ -14,8 +24,10 @@ class Mustache
|
|
14
24
|
super(name.to_s)
|
15
25
|
elsif @mustache.respond_to?(name)
|
16
26
|
@mustache.send(name)
|
27
|
+
elsif @mustache.raise_on_context_miss?
|
28
|
+
raise ContextMiss.new("Can't find #{name} in #{@mustache.inspect}")
|
17
29
|
else
|
18
|
-
|
30
|
+
''
|
19
31
|
end
|
20
32
|
end
|
21
33
|
end
|
data/lib/mustache/sinatra.rb
CHANGED
@@ -49,38 +49,18 @@ class Mustache
|
|
49
49
|
# This is called by Sinatra's `render` with the proper paths
|
50
50
|
# and, potentially, a block containing a sub-view
|
51
51
|
def render_mustache(template, data, opts, locals, &block)
|
52
|
-
|
52
|
+
# If you have Hurl::App::Views, namespace should be set to Hurl::App.
|
53
|
+
Mustache.view_namespace = options.namespace
|
53
54
|
|
54
|
-
# This is
|
55
|
-
#
|
56
|
-
|
57
|
-
namespace = options.namespace
|
55
|
+
# This is probably the same as options.views, but we'll set it anyway.
|
56
|
+
# It's used to tell Mustache where to look for view classes.
|
57
|
+
Mustache.view_path = options.mustaches
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
# e.g. Hurl::Views::Index
|
62
|
-
klass = namespace::Views.const_get(name)
|
59
|
+
# Grab the class!
|
60
|
+
klass = Mustache.view_class(template)
|
63
61
|
|
64
|
-
|
65
|
-
|
66
|
-
# load in the view.
|
67
|
-
require "#{file}".chomp('.rb')
|
68
|
-
klass = namespace::Views.const_get(name)
|
69
|
-
|
70
|
-
# compile and cache the template
|
71
|
-
klass.template = data
|
72
|
-
|
73
|
-
else
|
74
|
-
# Still nothing. Use the stache.
|
75
|
-
klass = Mustache
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
# Tell the view class its extension and path so finding partials
|
80
|
-
# works as expected.
|
81
|
-
if klass.template_extension != 'mustache'
|
82
|
-
klass.template_extension = 'mustache'
|
83
|
-
end
|
62
|
+
# Only cache the data if this isn't the generic base class.
|
63
|
+
klass.template = data unless klass == Mustache
|
84
64
|
|
85
65
|
# Confusingly Sinatra's `views` setting tells Mustache where the
|
86
66
|
# templates are found. It's fine, blame Chris.
|
data/lib/mustache/template.rb
CHANGED
@@ -9,9 +9,30 @@ class Mustache
|
|
9
9
|
#
|
10
10
|
# You shouldn't use this class directly.
|
11
11
|
class Template
|
12
|
+
# An UnclosedSection error is thrown when a {{# section }} is not
|
13
|
+
# closed.
|
14
|
+
#
|
15
|
+
# For example:
|
16
|
+
# {{# open }} blah {{/ close }}
|
17
|
+
class UnclosedSection < RuntimeError
|
18
|
+
attr_reader :message
|
19
|
+
|
20
|
+
# Report the line number of the offending unclosed section.
|
21
|
+
def initialize(source, matching_line, unclosed_section)
|
22
|
+
num = 0
|
23
|
+
|
24
|
+
source.split("\n").each_with_index do |line, i|
|
25
|
+
num = i + 1
|
26
|
+
break if line.strip == matching_line.strip
|
27
|
+
end
|
28
|
+
|
29
|
+
@message = "line #{num}: ##{unclosed_section.strip} is not closed"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
12
33
|
# Expects a Mustache template as a string along with a template
|
13
34
|
# path, which it uses to find partials.
|
14
|
-
def initialize(source, template_path = '.', template_extension = '
|
35
|
+
def initialize(source, template_path = '.', template_extension = 'mustache')
|
15
36
|
@source = source
|
16
37
|
@template_path = template_path
|
17
38
|
@template_extension = template_extension
|
@@ -85,9 +106,13 @@ class Mustache
|
|
85
106
|
# 4. Partial tags - {{< partial_name }}
|
86
107
|
def compile_tags(src)
|
87
108
|
res = ""
|
88
|
-
while src =~ /#{otag}(
|
109
|
+
while src =~ /#{otag}(#|=|!|<|\{)?(.+?)\1?#{ctag}+/
|
89
110
|
res << str($`)
|
90
111
|
case $1
|
112
|
+
when '#'
|
113
|
+
# Unclosed section - raise an error and
|
114
|
+
# report the line number
|
115
|
+
raise UnclosedSection.new(@source, $&, $2)
|
91
116
|
when '!'
|
92
117
|
# ignore comments
|
93
118
|
when '='
|
data/lib/mustache/version.rb
CHANGED
@@ -0,0 +1,81 @@
|
|
1
|
+
module Rack
|
2
|
+
module Bug
|
3
|
+
# MustachePanel is a Rack::Bug panel which tracks the time spent rendering
|
4
|
+
# Mustache views as well as all the variables accessed during view
|
5
|
+
# rendering.
|
6
|
+
#
|
7
|
+
# It can be used to track down slow partials and ensure you're only
|
8
|
+
# generating data you need.
|
9
|
+
#
|
10
|
+
# Also, it's fun.
|
11
|
+
class MustachePanel < Panel
|
12
|
+
require "rack/bug/panels/mustache_panel/mustache_extension"
|
13
|
+
|
14
|
+
# The view is responsible for rendering our panel. While Rack::Bug
|
15
|
+
# takes care of the nav, the content rendered by View is used for
|
16
|
+
# the panel itself.
|
17
|
+
class View < Mustache
|
18
|
+
self.path = ::File.dirname(__FILE__) + '/mustache_panel'
|
19
|
+
|
20
|
+
# We track the render times of all the Mustache views on this
|
21
|
+
# page load.
|
22
|
+
def times
|
23
|
+
MustachePanel.times.map do |key, value|
|
24
|
+
{ :key => key, :value => value }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Any variables used in this page load are collected and displayed.
|
29
|
+
def variables
|
30
|
+
vars = MustachePanel.variables.sort_by { |key, _| key.to_s }
|
31
|
+
vars.map do |key, value|
|
32
|
+
# Arrays can get too huge. Just show the first 10 to give you
|
33
|
+
# some idea.
|
34
|
+
if value.is_a?(Array) && value.size > 10
|
35
|
+
size = value.size
|
36
|
+
value = value.first(10)
|
37
|
+
value << "...and #{size - 10} more"
|
38
|
+
end
|
39
|
+
|
40
|
+
{ :key => key, :value => value.inspect }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Clear out our page load-specific variables.
|
46
|
+
def self.reset
|
47
|
+
Thread.current["rack.bug.mustache.times"] = {}
|
48
|
+
Thread.current["rack.bug.mustache.vars"] = {}
|
49
|
+
end
|
50
|
+
|
51
|
+
# The view render times for this page load
|
52
|
+
def self.times
|
53
|
+
Thread.current["rack.bug.mustache.times"] ||= {}
|
54
|
+
end
|
55
|
+
|
56
|
+
# The variables used on this page load
|
57
|
+
def self.variables
|
58
|
+
Thread.current["rack.bug.mustache.vars"] ||= {}
|
59
|
+
end
|
60
|
+
|
61
|
+
# The name of this Rack::Bug panel
|
62
|
+
def name
|
63
|
+
"mustache"
|
64
|
+
end
|
65
|
+
|
66
|
+
# The string used for our tab in Rack::Bug's navigation bar
|
67
|
+
def heading
|
68
|
+
"{{%.2fms}}" % self.class.times.values.inject(0.0) do |sum, obj|
|
69
|
+
sum + obj
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# The content of our Rack::Bug panel
|
74
|
+
def content
|
75
|
+
View.render
|
76
|
+
ensure
|
77
|
+
self.class.reset
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
if defined? Mustache
|
2
|
+
Mustache.class_eval do
|
3
|
+
alias_method :real_render, :render
|
4
|
+
|
5
|
+
def render(*args, &block)
|
6
|
+
out = ''
|
7
|
+
Rack::Bug::MustachePanel.times[self.class.name] = Benchmark.realtime do
|
8
|
+
out = real_render(*args, &block)
|
9
|
+
end
|
10
|
+
out
|
11
|
+
end
|
12
|
+
|
13
|
+
alias_method :to_html, :render
|
14
|
+
alias_method :to_text, :render
|
15
|
+
end
|
16
|
+
|
17
|
+
Mustache::Context.class_eval do
|
18
|
+
alias_method :real_get, :[]
|
19
|
+
|
20
|
+
def [](name)
|
21
|
+
return real_get(name) if name == :yield || !@mustache.respond_to?(name)
|
22
|
+
Rack::Bug::MustachePanel.variables[name] = real_get(name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<h3>Render Times</h3>
|
2
|
+
|
3
|
+
<table>
|
4
|
+
<tr>
|
5
|
+
<th>View</th>
|
6
|
+
<th>Render Time</th>
|
7
|
+
</tr>
|
8
|
+
|
9
|
+
{{# times }}
|
10
|
+
<tr>
|
11
|
+
<td>{{ key }}</td>
|
12
|
+
<td>{{ value }}</td>
|
13
|
+
</tr>
|
14
|
+
{{/ times }}
|
15
|
+
</table>
|
16
|
+
|
17
|
+
<h3>Variables</h3>
|
18
|
+
|
19
|
+
<table>
|
20
|
+
<tr>
|
21
|
+
<th>Name</th>
|
22
|
+
<th>Value</th>
|
23
|
+
</tr>
|
24
|
+
|
25
|
+
{{# variables }}
|
26
|
+
<tr>
|
27
|
+
<td>{{ key }}</td>
|
28
|
+
<td>{{ value }}</td>
|
29
|
+
</tr>
|
30
|
+
{{/ variables }}
|
31
|
+
</table>
|
32
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
module TestViews; end
|
4
|
+
|
5
|
+
class AutoloadingTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
Mustache.view_path = File.dirname(__FILE__) + '/../examples'
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_autoload
|
11
|
+
klass = Mustache.view_class(:Comments)
|
12
|
+
assert_equal Comments, klass
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_autoload_lowercase
|
16
|
+
klass = Mustache.view_class(:comments)
|
17
|
+
assert_equal Comments, klass
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_autoload_nil
|
21
|
+
klass = Mustache.view_class(nil)
|
22
|
+
assert_equal Mustache, klass
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_autoload_empty_string
|
26
|
+
klass = Mustache.view_class('')
|
27
|
+
assert_equal Mustache, klass
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_namespaced_autoload
|
31
|
+
Mustache.view_namespace = TestViews
|
32
|
+
klass = Mustache.view_class('Namespaced')
|
33
|
+
assert_equal TestViews::Namespaced, klass
|
34
|
+
assert_equal <<-end_render.strip, klass.render
|
35
|
+
<h1>Dragon < Tiger</h1>
|
36
|
+
end_render
|
37
|
+
end
|
38
|
+
end
|
data/test/mustache_test.rb
CHANGED
@@ -224,6 +224,29 @@ data
|
|
224
224
|
end
|
225
225
|
end
|
226
226
|
|
227
|
+
def test_reports_unclosed_sections
|
228
|
+
instance = Mustache.new
|
229
|
+
instance[:list] = [ :item => 1234 ]
|
230
|
+
instance.template = '{{#list}} <li>{{item}}</li> {{/gist}}'
|
231
|
+
|
232
|
+
assert_raise Mustache::Template::UnclosedSection do
|
233
|
+
instance.render
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_unclosed_sections_reports_the_line_number
|
238
|
+
instance = Mustache.new
|
239
|
+
instance[:list] = [ :item => 1234 ]
|
240
|
+
instance.template = "hi\nmom\n{{#list}} <li>{{item}}</li> {{/gist}}"
|
241
|
+
|
242
|
+
begin
|
243
|
+
instance.render
|
244
|
+
rescue => e
|
245
|
+
end
|
246
|
+
|
247
|
+
assert e.message.include?('line 3')
|
248
|
+
end
|
249
|
+
|
227
250
|
def test_enumerable_sections_accept_a_hash_as_a_context
|
228
251
|
instance = Mustache.new
|
229
252
|
instance[:list] = { :item => 1234 }
|
@@ -240,6 +263,31 @@ data
|
|
240
263
|
assert_equal '<li>1234</li>', instance.render.strip
|
241
264
|
end
|
242
265
|
|
266
|
+
def test_not_found_in_context_renders_empty_string
|
267
|
+
instance = Mustache.new
|
268
|
+
instance.template = '{{#list}} <li>{{item}}</li> {{/list}}'
|
269
|
+
|
270
|
+
assert_equal '', instance.render.strip
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_not_found_in_nested_context_renders_empty_string
|
274
|
+
instance = Mustache.new
|
275
|
+
instance[:list] = { :item => 1234 }
|
276
|
+
instance.template = '{{#list}} <li>{{prefix}}{{item}}</li> {{/list}}'
|
277
|
+
|
278
|
+
assert_equal '<li>1234</li>', instance.render.strip
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_not_found_in_context_raises_when_asked_to
|
282
|
+
instance = Mustache.new
|
283
|
+
instance.raise_on_context_miss = true
|
284
|
+
instance.template = '{{#list}} <li>{{item}}</li> {{/list}}'
|
285
|
+
|
286
|
+
assert_raises Mustache::ContextMiss do
|
287
|
+
instance.render.strip
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
243
291
|
def test_knows_when_its_been_compiled_when_set_with_string
|
244
292
|
klass = Class.new(Mustache)
|
245
293
|
|
@@ -250,7 +298,7 @@ data
|
|
250
298
|
|
251
299
|
def test_knows_when_its_been_compiled_when_using_a_file_template
|
252
300
|
klass = Class.new(Simple)
|
253
|
-
klass.template_file = File.dirname(__FILE__) + '/../examples/simple.
|
301
|
+
klass.template_file = File.dirname(__FILE__) + '/../examples/simple.mustache'
|
254
302
|
|
255
303
|
assert ! klass.compiled?
|
256
304
|
klass.render
|
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: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Wanstrath
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-27 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -36,34 +36,40 @@ files:
|
|
36
36
|
- benchmarks/simple.erb
|
37
37
|
- benchmarks/speed.rb
|
38
38
|
- contrib/mustache.vim
|
39
|
-
- examples/comments.
|
39
|
+
- examples/comments.mustache
|
40
40
|
- examples/comments.rb
|
41
|
-
- examples/complex_view.
|
41
|
+
- examples/complex_view.mustache
|
42
42
|
- examples/complex_view.rb
|
43
|
-
- examples/delimiters.
|
43
|
+
- examples/delimiters.mustache
|
44
44
|
- examples/delimiters.rb
|
45
|
-
- examples/double_section.
|
45
|
+
- examples/double_section.mustache
|
46
46
|
- examples/double_section.rb
|
47
|
-
- examples/escaped.
|
47
|
+
- examples/escaped.mustache
|
48
48
|
- examples/escaped.rb
|
49
|
-
- examples/inner_partial.
|
49
|
+
- examples/inner_partial.mustache
|
50
50
|
- examples/inner_partial.txt
|
51
|
+
- examples/namespaced.mustache
|
52
|
+
- examples/namespaced.rb
|
51
53
|
- examples/passenger.conf
|
52
54
|
- examples/passenger.rb
|
53
|
-
- examples/simple.
|
55
|
+
- examples/simple.mustache
|
54
56
|
- examples/simple.rb
|
55
|
-
- examples/template_partial.
|
57
|
+
- examples/template_partial.mustache
|
56
58
|
- examples/template_partial.rb
|
57
59
|
- examples/template_partial.txt
|
58
|
-
- examples/unescaped.
|
60
|
+
- examples/unescaped.mustache
|
59
61
|
- examples/unescaped.rb
|
60
|
-
- examples/view_partial.
|
62
|
+
- examples/view_partial.mustache
|
61
63
|
- examples/view_partial.rb
|
62
64
|
- lib/mustache.rb
|
63
65
|
- lib/mustache/context.rb
|
64
66
|
- lib/mustache/sinatra.rb
|
65
67
|
- lib/mustache/template.rb
|
66
68
|
- lib/mustache/version.rb
|
69
|
+
- lib/rack/bug/panels/mustache_panel.rb
|
70
|
+
- lib/rack/bug/panels/mustache_panel/mustache_extension.rb
|
71
|
+
- lib/rack/bug/panels/mustache_panel/view.mustache
|
72
|
+
- test/autoloading_test.rb
|
67
73
|
- test/mustache_test.rb
|
68
74
|
has_rdoc: true
|
69
75
|
homepage: http://github.com/defunkt/mustache
|
@@ -94,12 +100,14 @@ signing_key:
|
|
94
100
|
specification_version: 3
|
95
101
|
summary: Mustache is a framework-agnostic way to render logic-free views.
|
96
102
|
test_files:
|
103
|
+
- test/autoloading_test.rb
|
97
104
|
- test/mustache_test.rb
|
98
105
|
- examples/comments.rb
|
99
106
|
- examples/complex_view.rb
|
100
107
|
- examples/delimiters.rb
|
101
108
|
- examples/double_section.rb
|
102
109
|
- examples/escaped.rb
|
110
|
+
- examples/namespaced.rb
|
103
111
|
- examples/passenger.rb
|
104
112
|
- examples/simple.rb
|
105
113
|
- examples/template_partial.rb
|