mustache 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Rack::Bug](http://img.skitch.com/20091027-xyf4h1yxnefpp7usyddrcmc7dn.png)][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
|