tilt 0.6 → 0.7
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/README.md +6 -0
- data/Rakefile +33 -32
- data/TEMPLATES.md +13 -2
- data/lib/tilt.rb +194 -81
- data/test/tilt_buildertemplate_test.rb +1 -1
- data/test/tilt_compilesite_test.rb +62 -0
- data/test/tilt_erbtemplate_test.rb +104 -2
- data/test/tilt_erubistemplate_test.rb +9 -1
- data/test/tilt_hamltemplate_test.rb +54 -1
- data/test/tilt_liquidtemplate_test.rb +1 -1
- data/test/tilt_mustachetemplate_test.rb +1 -4
- data/test/tilt_rdiscounttemplate_test.rb +3 -3
- data/test/tilt_rdoctemplate_test.rb +1 -1
- data/test/tilt_stringtemplate_test.rb +87 -1
- data/test/tilt_template_test.rb +28 -23
- data/tilt.gemspec +4 -2
- metadata +16 -3
data/README.md
CHANGED
@@ -33,6 +33,12 @@ Support for these template engines is included with the package:
|
|
33
33
|
RDiscount .markdown rdiscount
|
34
34
|
RedCloth .textile redcloth
|
35
35
|
|
36
|
+
See [TEMPLATES.md][t] for detailed information on template engine
|
37
|
+
options and supported features.
|
38
|
+
|
39
|
+
[t]: http://github.com/rtomayko/tilt/blob/master/TEMPLATES.md
|
40
|
+
"Tilt Template Engine Documentation"
|
41
|
+
|
36
42
|
Basic Usage
|
37
43
|
-----------
|
38
44
|
|
data/Rakefile
CHANGED
@@ -16,38 +16,39 @@ end
|
|
16
16
|
|
17
17
|
# PACKAGING =================================================================
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
def package(ext='')
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
desc 'Build packages'
|
27
|
-
task :package => %w[.gem .tar.gz].map {|e| package(e)}
|
28
|
-
|
29
|
-
desc 'Build and install as local gem'
|
30
|
-
task :install => package('.gem') do
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
directory '
|
35
|
-
|
36
|
-
file package('.gem') => %w[
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
file package('.tar.gz') => %w[
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
desc 'Upload gem and tar.gz distributables to rubyforge'
|
46
|
-
task :release => [package('.gem'), package('.tar.gz')] do |t|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
19
|
+
if defined?(Gem)
|
20
|
+
SPEC = eval(File.read('tilt.gemspec'))
|
21
|
+
|
22
|
+
def package(ext='')
|
23
|
+
"pkg/tilt-#{SPEC.version}" + ext
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Build packages'
|
27
|
+
task :package => %w[.gem .tar.gz].map {|e| package(e)}
|
28
|
+
|
29
|
+
desc 'Build and install as local gem'
|
30
|
+
task :install => package('.gem') do
|
31
|
+
sh "gem install #{package('.gem')}"
|
32
|
+
end
|
33
|
+
|
34
|
+
directory 'pkg/'
|
35
|
+
|
36
|
+
file package('.gem') => %w[pkg/ tilt.gemspec] + SPEC.files do |f|
|
37
|
+
sh "gem build tilt.gemspec"
|
38
|
+
mv File.basename(f.name), f.name
|
39
|
+
end
|
40
|
+
|
41
|
+
file package('.tar.gz') => %w[pkg/] + SPEC.files do |f|
|
42
|
+
sh "git archive --format=tar HEAD | gzip > #{f.name}"
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'Upload gem and tar.gz distributables to rubyforge'
|
46
|
+
task :release => [package('.gem'), package('.tar.gz')] do |t|
|
47
|
+
sh <<-SH
|
48
|
+
rubyforge add_release sinatra tilt #{SPEC.version} #{package('.gem')} &&
|
49
|
+
rubyforge add_file sinatra tilt #{SPEC.version} #{package('.tar.gz')}
|
50
|
+
SH
|
51
|
+
end
|
51
52
|
end
|
52
53
|
|
53
54
|
# GEMSPEC ===================================================================
|
data/TEMPLATES.md
CHANGED
@@ -67,6 +67,12 @@ of any combination of the following characters:
|
|
67
67
|
The `$SAFE` level; when set, ERB code will be run in a
|
68
68
|
separate thread with `$SAFE` set to the provided level.
|
69
69
|
|
70
|
+
#### `:outvar => '_erbout'`
|
71
|
+
|
72
|
+
The name of the variable used to accumulate template output. This can be
|
73
|
+
any valid Ruby expression but must be assignable. By default a local
|
74
|
+
variable named `_erbout` is used.
|
75
|
+
|
70
76
|
### See also
|
71
77
|
|
72
78
|
* [ERB documentation](http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html)
|
@@ -98,14 +104,19 @@ Set pattern for embedded Ruby code.
|
|
98
104
|
|
99
105
|
See the [ERB](#erb) template documentation for examples, usage, and options.
|
100
106
|
|
101
|
-
|
102
|
-
|
107
|
+
#### `:outvar => '_erbout'`
|
108
|
+
|
109
|
+
The name of the variable used to accumulate template output. This can be
|
110
|
+
any valid Ruby expression but must be assignable. By default a local
|
111
|
+
variable named `_erbout` is used.
|
103
112
|
|
104
113
|
### See also
|
105
114
|
|
106
115
|
* [Erubis Home](http://www.kuwata-lab.com/erubis/)
|
107
116
|
* [Erubis User's Guide](http://www.kuwata-lab.com/erubis/users-guide.html)
|
108
117
|
|
118
|
+
__NOTE:__ It's suggested that your program `require 'erubis'` at load time when
|
119
|
+
using this template engine within a threaded environment.
|
109
120
|
|
110
121
|
<a name='haml'></a>
|
111
122
|
Haml (`haml`)
|
data/lib/tilt.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
module Tilt
|
2
|
-
VERSION = '0.
|
2
|
+
VERSION = '0.7'
|
3
3
|
|
4
4
|
@template_mappings = {}
|
5
5
|
|
6
|
-
# Hash of template path pattern => template implementation
|
7
|
-
# class mappings.
|
6
|
+
# Hash of template path pattern => template implementation class mappings.
|
8
7
|
def self.mappings
|
9
8
|
@template_mappings
|
10
9
|
end
|
@@ -25,7 +24,7 @@ module Tilt
|
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
28
|
-
# Lookup a template class
|
27
|
+
# Lookup a template class for the given filename or file
|
29
28
|
# extension. Return nil when no implementation is found.
|
30
29
|
def self.[](file)
|
31
30
|
if @template_mappings.key?(pattern = file.to_s.downcase)
|
@@ -44,9 +43,24 @@ module Tilt
|
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
46
|
+
# Mixin allowing template compilation on scope objects.
|
47
|
+
#
|
48
|
+
# Including this module in scope objects passed to Template#render
|
49
|
+
# causes template source to be compiled to methods the first time they're
|
50
|
+
# used. This can yield significant (5x-10x) performance increases for
|
51
|
+
# templates that support it (ERB, Erubis, Builder).
|
52
|
+
#
|
53
|
+
# It's also possible (though not recommended) to include this module in
|
54
|
+
# Object to enable template compilation globally. The downside is that
|
55
|
+
# the template methods will polute the global namespace and could lead to
|
56
|
+
# unexpected behavior.
|
57
|
+
module CompileSite
|
58
|
+
def __tilt__
|
59
|
+
end
|
60
|
+
end
|
47
61
|
|
48
62
|
# Base class for template implementations. Subclasses must implement
|
49
|
-
# the #
|
63
|
+
# the #prepare method and one of the #evaluate or #template_source
|
50
64
|
# methods.
|
51
65
|
class Template
|
52
66
|
# Template source; loaded from a file or given directly.
|
@@ -63,52 +77,55 @@ module Tilt
|
|
63
77
|
# interface.
|
64
78
|
attr_reader :options
|
65
79
|
|
80
|
+
# Used to determine if this class's initialize_engine method has
|
81
|
+
# been called yet.
|
82
|
+
@engine_initialized = false
|
83
|
+
class << self
|
84
|
+
attr_accessor :engine_initialized
|
85
|
+
alias engine_initialized? engine_initialized
|
86
|
+
end
|
87
|
+
|
66
88
|
# Create a new template with the file, line, and options specified. By
|
67
|
-
# default, template data is read from the file
|
68
|
-
#
|
69
|
-
#
|
89
|
+
# default, template data is read from the file. When a block is given,
|
90
|
+
# it should read template data and return as a String. When file is nil,
|
91
|
+
# a block is required.
|
70
92
|
#
|
71
|
-
#
|
72
|
-
# time this template subclass has been initialized.
|
93
|
+
# All arguments are optional.
|
73
94
|
def initialize(file=nil, line=1, options={}, &block)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
95
|
+
@file, @line, @options = nil, 1, {}
|
96
|
+
|
97
|
+
[options, line, file].compact.each do |arg|
|
98
|
+
case
|
99
|
+
when arg.respond_to?(:to_str) ; @file = arg.to_str
|
100
|
+
when arg.respond_to?(:to_int) ; @line = arg.to_int
|
101
|
+
when arg.respond_to?(:to_hash) ; @options = arg.to_hash
|
102
|
+
else raise TypeError
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
raise ArgumentError, "file or block required" if (@file || block).nil?
|
107
|
+
|
108
|
+
# call the initialize_engine method if this is the very first time
|
109
|
+
# an instance of this class has been created.
|
110
|
+
if !self.class.engine_initialized?
|
83
111
|
initialize_engine
|
84
112
|
self.class.engine_initialized = true
|
85
113
|
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# Called once and only once for each template subclass the first time
|
89
|
-
# the template class is initialized. This should be used to require the
|
90
|
-
# underlying template library and perform any initial setup.
|
91
|
-
def initialize_engine
|
92
|
-
end
|
93
|
-
@engine_initialized = false
|
94
|
-
class << self ; attr_accessor :engine_initialized ; end
|
95
114
|
|
115
|
+
# used to generate unique method names for template compilation
|
116
|
+
stamp = (Time.now.to_f * 10000).to_i
|
117
|
+
@_prefix = "__tilt_O#{object_id.to_s(16)}T#{stamp.to_s(16)}"
|
96
118
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
if @data.nil?
|
102
|
-
@data = @reader.call(self)
|
103
|
-
compile!
|
104
|
-
end
|
119
|
+
# load template data and prepare
|
120
|
+
@reader = block || lambda { |t| File.read(@file) }
|
121
|
+
@data = @reader.call(self)
|
122
|
+
prepare
|
105
123
|
end
|
106
124
|
|
107
125
|
# Render the template in the given scope with the locals specified. If a
|
108
126
|
# block is given, it is typically available within the template via
|
109
127
|
# +yield+.
|
110
128
|
def render(scope=Object.new, locals={}, &block)
|
111
|
-
compile
|
112
129
|
evaluate scope, locals || {}, &block
|
113
130
|
end
|
114
131
|
|
@@ -128,26 +145,56 @@ module Tilt
|
|
128
145
|
end
|
129
146
|
|
130
147
|
protected
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
148
|
+
# Called once and only once for each template subclass the first time
|
149
|
+
# the template class is initialized. This should be used to require the
|
150
|
+
# underlying template library and perform any initial setup.
|
151
|
+
def initialize_engine
|
152
|
+
end
|
153
|
+
|
154
|
+
# Do whatever preparation is necessary to setup the underlying template
|
155
|
+
# engine. Called immediately after template data is loaded. Instance
|
156
|
+
# variables set in this method are available when #evaluate is called.
|
134
157
|
#
|
135
158
|
# Subclasses must provide an implementation of this method.
|
136
|
-
def
|
137
|
-
|
159
|
+
def prepare
|
160
|
+
if respond_to?(:compile!)
|
161
|
+
# backward compat with tilt < 0.6; just in case
|
162
|
+
warn 'Tilt::Template#compile! is deprecated; implement #prepare instead.'
|
163
|
+
compile!
|
164
|
+
else
|
165
|
+
raise NotImplementedError
|
166
|
+
end
|
138
167
|
end
|
139
168
|
|
140
|
-
# Process the template and return the result.
|
141
|
-
#
|
169
|
+
# Process the template and return the result. When the scope mixes in
|
170
|
+
# the Tilt::CompileSite module, the template is compiled to a method and
|
171
|
+
# reused given identical locals keys. When the scope object
|
172
|
+
# does not mix in the CompileSite module, the template source is
|
173
|
+
# evaluated with instance_eval. In any case, template executation
|
174
|
+
# is guaranteed to be performed in the scope object with the locals
|
175
|
+
# specified and with support for yielding to the block.
|
142
176
|
def evaluate(scope, locals, &block)
|
143
|
-
|
144
|
-
|
145
|
-
|
177
|
+
if scope.respond_to?(:__tilt__)
|
178
|
+
method_name = compiled_method_name(locals.keys.hash)
|
179
|
+
if scope.respond_to?(method_name)
|
180
|
+
# fast path
|
181
|
+
scope.send method_name, locals, &block
|
182
|
+
else
|
183
|
+
# compile first and then run
|
184
|
+
compile_template_method(method_name, locals)
|
185
|
+
scope.send method_name, locals, &block
|
186
|
+
end
|
187
|
+
else
|
188
|
+
source, offset = local_assignment_code(locals)
|
189
|
+
source = [source, template_source].join("\n")
|
190
|
+
scope.instance_eval source, eval_file, line - offset
|
191
|
+
end
|
146
192
|
end
|
147
193
|
|
148
194
|
# Return a string containing the (Ruby) source code for the template. The
|
149
195
|
# default Template#evaluate implementation requires this method be
|
150
|
-
# defined
|
196
|
+
# defined and guarantees correct file/line handling, custom scopes, and
|
197
|
+
# support for template compilation when the scope object allows it.
|
151
198
|
def template_source
|
152
199
|
raise NotImplementedError
|
153
200
|
end
|
@@ -159,6 +206,41 @@ module Tilt
|
|
159
206
|
[source.join("\n"), source.length]
|
160
207
|
end
|
161
208
|
|
209
|
+
def compiled_method_name(locals_hash)
|
210
|
+
"#{@_prefix}L#{locals_hash.to_s(16).sub('-', 'n')}"
|
211
|
+
end
|
212
|
+
|
213
|
+
def compile_template_method(method_name, locals)
|
214
|
+
source, offset = local_assignment_code(locals)
|
215
|
+
source = [source, template_source].join("\n")
|
216
|
+
offset += 1
|
217
|
+
|
218
|
+
# add the new method
|
219
|
+
CompileSite.module_eval <<-RUBY, eval_file, line - offset
|
220
|
+
def #{method_name}(locals)
|
221
|
+
#{source}
|
222
|
+
end
|
223
|
+
RUBY
|
224
|
+
|
225
|
+
# setup a finalizer to remove the newly added method
|
226
|
+
ObjectSpace.define_finalizer self,
|
227
|
+
Template.compiled_template_method_remover(CompileSite, method_name)
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.compiled_template_method_remover(site, method_name)
|
231
|
+
proc { |oid| garbage_collect_compiled_template_method(site, method_name) }
|
232
|
+
end
|
233
|
+
|
234
|
+
def self.garbage_collect_compiled_template_method(site, method_name)
|
235
|
+
site.module_eval do
|
236
|
+
begin
|
237
|
+
remove_method(method_name)
|
238
|
+
rescue NameError
|
239
|
+
# method was already removed (ruby >= 1.9)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
162
244
|
def require_template_library(name)
|
163
245
|
if Thread.list.size > 1
|
164
246
|
warn "WARN: tilt autoloading '#{name}' in a non thread-safe way; " +
|
@@ -174,7 +256,7 @@ module Tilt
|
|
174
256
|
# cache = Tilt::Cache.new
|
175
257
|
# cache.fetch(path, line, options) { Tilt.new(path, line, options) }
|
176
258
|
#
|
177
|
-
# Subsequent invocations return the already
|
259
|
+
# Subsequent invocations return the already loaded template object.
|
178
260
|
class Cache
|
179
261
|
def initialize
|
180
262
|
@cache = {}
|
@@ -196,7 +278,7 @@ module Tilt
|
|
196
278
|
# The template source is evaluated as a Ruby string. The #{} interpolation
|
197
279
|
# syntax can be used to generated dynamic output.
|
198
280
|
class StringTemplate < Template
|
199
|
-
def
|
281
|
+
def prepare
|
200
282
|
@code = "%Q{#{data}}"
|
201
283
|
end
|
202
284
|
|
@@ -214,8 +296,9 @@ module Tilt
|
|
214
296
|
require_template_library 'erb' unless defined? ::ERB
|
215
297
|
end
|
216
298
|
|
217
|
-
def
|
218
|
-
@
|
299
|
+
def prepare
|
300
|
+
@outvar = (options[:outvar] || '_erbout').to_s
|
301
|
+
@engine = ::ERB.new(data, options[:safe], options[:trim], @outvar)
|
219
302
|
end
|
220
303
|
|
221
304
|
def template_source
|
@@ -223,22 +306,23 @@ module Tilt
|
|
223
306
|
end
|
224
307
|
|
225
308
|
def evaluate(scope, locals, &block)
|
226
|
-
|
227
|
-
source = [source, template_source].join("\n")
|
228
|
-
|
229
|
-
original_out_buf =
|
230
|
-
scope.instance_variables.any? { |var| var.to_sym == :@_out_buf } &&
|
231
|
-
scope.instance_variable_get(:@_out_buf)
|
232
|
-
|
233
|
-
scope.instance_eval source, eval_file, line - offset
|
234
|
-
|
235
|
-
output = scope.instance_variable_get(:@_out_buf)
|
236
|
-
scope.instance_variable_set(:@_out_buf, original_out_buf)
|
237
|
-
|
238
|
-
output
|
309
|
+
preserve_outvar_value(scope) { super }
|
239
310
|
end
|
240
311
|
|
241
312
|
private
|
313
|
+
# Retains the previous value of outvar when configured to use
|
314
|
+
# an instance variable. This allows multiple templates to be rendered
|
315
|
+
# within the context of an object without overwriting the outvar.
|
316
|
+
def preserve_outvar_value(scope)
|
317
|
+
if @outvar[0] == ?@
|
318
|
+
previous = scope.instance_variable_get(@outvar)
|
319
|
+
output = yield
|
320
|
+
scope.instance_variable_set(@outvar, previous)
|
321
|
+
output
|
322
|
+
else
|
323
|
+
yield
|
324
|
+
end
|
325
|
+
end
|
242
326
|
|
243
327
|
# ERB generates a line to specify the character coding of the generated
|
244
328
|
# source in 1.9. Account for this in the line offset.
|
@@ -259,13 +343,17 @@ module Tilt
|
|
259
343
|
require_template_library 'erubis' unless defined? ::Erubis
|
260
344
|
end
|
261
345
|
|
262
|
-
def
|
263
|
-
|
346
|
+
def prepare
|
347
|
+
@options.merge!(:preamble => false, :postamble => false)
|
348
|
+
@outvar = (options.delete(:outvar) || '_erbout').to_s
|
264
349
|
@engine = ::Erubis::Eruby.new(data, options)
|
265
350
|
end
|
266
351
|
|
267
|
-
|
352
|
+
def template_source
|
353
|
+
["#{@outvar} = _buf = ''", @engine.src, "_buf.to_s"].join(";")
|
354
|
+
end
|
268
355
|
|
356
|
+
private
|
269
357
|
# Erubis doesn't have ERB's line-off-by-one under 1.9 problem. Override
|
270
358
|
# and adjust back.
|
271
359
|
if RUBY_VERSION >= '1.9.0'
|
@@ -285,15 +373,37 @@ module Tilt
|
|
285
373
|
require_template_library 'haml' unless defined? ::Haml::Engine
|
286
374
|
end
|
287
375
|
|
288
|
-
def
|
376
|
+
def prepare
|
289
377
|
@engine = ::Haml::Engine.new(data, haml_options)
|
290
378
|
end
|
291
379
|
|
292
|
-
|
293
|
-
|
380
|
+
# Precompiled Haml source. Taken from the precompiled_with_ambles
|
381
|
+
# method in Haml::Precompiler:
|
382
|
+
# http://github.com/nex3/haml/blob/master/lib/haml/precompiler.rb#L111-126
|
383
|
+
def template_source
|
384
|
+
@engine.instance_eval do
|
385
|
+
<<-RUBY
|
386
|
+
_haml_locals = locals
|
387
|
+
begin
|
388
|
+
extend Haml::Helpers
|
389
|
+
_hamlout = @haml_buffer = Haml::Buffer.new(@haml_buffer, #{options_for_buffer.inspect})
|
390
|
+
_erbout = _hamlout.buffer
|
391
|
+
__in_erb_template = true
|
392
|
+
#{precompiled}
|
393
|
+
#{precompiled_method_return_value}
|
394
|
+
ensure
|
395
|
+
@haml_buffer = @haml_buffer.upper
|
396
|
+
end
|
397
|
+
RUBY
|
398
|
+
end
|
294
399
|
end
|
295
400
|
|
296
401
|
private
|
402
|
+
def local_assignment_code(locals)
|
403
|
+
source, offset = super
|
404
|
+
[source, offset + 6]
|
405
|
+
end
|
406
|
+
|
297
407
|
def haml_options
|
298
408
|
options.merge(:filename => eval_file, :line => line)
|
299
409
|
end
|
@@ -310,12 +420,12 @@ module Tilt
|
|
310
420
|
require_template_library 'sass' unless defined? ::Sass::Engine
|
311
421
|
end
|
312
422
|
|
313
|
-
def
|
423
|
+
def prepare
|
314
424
|
@engine = ::Sass::Engine.new(data, sass_options)
|
315
425
|
end
|
316
426
|
|
317
427
|
def evaluate(scope, locals, &block)
|
318
|
-
@engine.render
|
428
|
+
@output ||= @engine.render
|
319
429
|
end
|
320
430
|
|
321
431
|
private
|
@@ -335,7 +445,7 @@ module Tilt
|
|
335
445
|
require_template_library 'less' unless defined? ::Less::Engine
|
336
446
|
end
|
337
447
|
|
338
|
-
def
|
448
|
+
def prepare
|
339
449
|
@engine = ::Less::Engine.new(data)
|
340
450
|
end
|
341
451
|
|
@@ -345,6 +455,7 @@ module Tilt
|
|
345
455
|
end
|
346
456
|
register 'less', LessTemplate
|
347
457
|
|
458
|
+
|
348
459
|
# Builder template implementation. See:
|
349
460
|
# http://builder.rubyforge.org/
|
350
461
|
class BuilderTemplate < Template
|
@@ -352,7 +463,7 @@ module Tilt
|
|
352
463
|
require_template_library 'builder' unless defined?(::Builder)
|
353
464
|
end
|
354
465
|
|
355
|
-
def
|
466
|
+
def prepare
|
356
467
|
end
|
357
468
|
|
358
469
|
def evaluate(scope, locals, &block)
|
@@ -391,7 +502,7 @@ module Tilt
|
|
391
502
|
require_template_library 'liquid' unless defined? ::Liquid::Template
|
392
503
|
end
|
393
504
|
|
394
|
-
def
|
505
|
+
def prepare
|
395
506
|
@engine = ::Liquid::Template.parse(data)
|
396
507
|
end
|
397
508
|
|
@@ -424,7 +535,7 @@ module Tilt
|
|
424
535
|
require_template_library 'rdiscount' unless defined? ::RDiscount
|
425
536
|
end
|
426
537
|
|
427
|
-
def
|
538
|
+
def prepare
|
428
539
|
@engine = RDiscount.new(data, *flags)
|
429
540
|
end
|
430
541
|
|
@@ -444,7 +555,7 @@ module Tilt
|
|
444
555
|
require_template_library 'redcloth' unless defined? ::RedCloth
|
445
556
|
end
|
446
557
|
|
447
|
-
def
|
558
|
+
def prepare
|
448
559
|
@engine = RedCloth.new(data)
|
449
560
|
end
|
450
561
|
|
@@ -468,7 +579,7 @@ module Tilt
|
|
468
579
|
require_template_library 'mustache' unless defined? ::Mustache
|
469
580
|
end
|
470
581
|
|
471
|
-
def
|
582
|
+
def prepare
|
472
583
|
Mustache.view_namespace = options[:namespace]
|
473
584
|
Mustache.view_path = options[:view_path] || options[:mustaches]
|
474
585
|
@engine = options[:view] || Mustache.view_class(name)
|
@@ -502,6 +613,7 @@ module Tilt
|
|
502
613
|
end
|
503
614
|
register 'mustache', MustacheTemplate
|
504
615
|
|
616
|
+
|
505
617
|
# RDoc template. See:
|
506
618
|
# http://rdoc.rubyforge.org/
|
507
619
|
#
|
@@ -516,7 +628,7 @@ module Tilt
|
|
516
628
|
end
|
517
629
|
end
|
518
630
|
|
519
|
-
def
|
631
|
+
def prepare
|
520
632
|
markup = RDoc::Markup::ToHtml.new
|
521
633
|
@engine = markup.convert(data)
|
522
634
|
end
|
@@ -527,6 +639,7 @@ module Tilt
|
|
527
639
|
end
|
528
640
|
register 'rdoc', RDocTemplate
|
529
641
|
|
642
|
+
|
530
643
|
# CoffeeScript info:
|
531
644
|
# http://jashkenas.github.com/coffee-script/
|
532
645
|
class CoffeeTemplate < Template
|
@@ -534,7 +647,7 @@ module Tilt
|
|
534
647
|
require_template_library 'coffee-script' unless defined? ::CoffeeScript
|
535
648
|
end
|
536
649
|
|
537
|
-
def
|
650
|
+
def prepare
|
538
651
|
@engine = ::CoffeeScript::compile(data, options)
|
539
652
|
end
|
540
653
|
|
@@ -9,7 +9,7 @@ begin
|
|
9
9
|
assert_equal Tilt::BuilderTemplate, Tilt['test.xml.builder']
|
10
10
|
end
|
11
11
|
|
12
|
-
test "
|
12
|
+
test "preparing and evaluating the template on #render" do
|
13
13
|
template = Tilt::BuilderTemplate.new { |t| "xml.em 'Hello World!'" }
|
14
14
|
assert_equal "<em>Hello World!</em>\n", template.render
|
15
15
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'contest'
|
2
|
+
require 'tilt'
|
3
|
+
|
4
|
+
class CompileSiteTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
GC.start
|
7
|
+
end
|
8
|
+
|
9
|
+
class CompilingTemplate < Tilt::Template
|
10
|
+
def prepare
|
11
|
+
end
|
12
|
+
|
13
|
+
def template_source
|
14
|
+
@data.inspect
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Scope
|
19
|
+
include Tilt::CompileSite
|
20
|
+
end
|
21
|
+
|
22
|
+
test "compiling template source to a method" do
|
23
|
+
template = CompilingTemplate.new { |t| "Hello World!" }
|
24
|
+
template.render(Scope.new)
|
25
|
+
method_name = template.send(:compiled_method_name, [].hash)
|
26
|
+
method_name = method_name.to_sym if Symbol === Kernel.methods.first
|
27
|
+
assert Tilt::CompileSite.instance_methods.include?(method_name),
|
28
|
+
"CompileSite.instance_methods.include?(#{method_name.inspect})"
|
29
|
+
assert Scope.new.respond_to?(method_name),
|
30
|
+
"scope.respond_to?(#{method_name.inspect})"
|
31
|
+
end
|
32
|
+
|
33
|
+
test 'garbage collecting compiled methods' do
|
34
|
+
template = CompilingTemplate.new { '' }
|
35
|
+
method_name = template.send(:compiled_method_name, [].hash)
|
36
|
+
template.render(Scope.new)
|
37
|
+
assert Scope.new.respond_to?(method_name)
|
38
|
+
Tilt::Template.send(
|
39
|
+
:garbage_collect_compiled_template_method,
|
40
|
+
Tilt::CompileSite,
|
41
|
+
method_name
|
42
|
+
)
|
43
|
+
assert !Scope.new.respond_to?(method_name), "compiled method not removed"
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.create_and_destroy_template
|
47
|
+
template = CompilingTemplate.new { 'Hello World' }
|
48
|
+
template.render(Scope.new)
|
49
|
+
method_name = template.send(:compiled_method_name, [].hash)
|
50
|
+
method_name = method_name.to_sym if Symbol === Kernel.methods.first
|
51
|
+
[template.object_id, method_name]
|
52
|
+
end
|
53
|
+
|
54
|
+
finalized_object_id, finalized_method_name = create_and_destroy_template
|
55
|
+
|
56
|
+
test "triggering compiled method gc finalizer" do
|
57
|
+
assert !Tilt::CompileSite.instance_methods.include?(finalized_method_name),
|
58
|
+
"CompileSite.instance_methods.include?(#{finalized_method_name.inspect})"
|
59
|
+
assert !Scope.new.respond_to?(finalized_method_name),
|
60
|
+
"Scope.new.respond_to?(#{finalized_method_name.inspect})"
|
61
|
+
end
|
62
|
+
end
|
@@ -12,7 +12,7 @@ class ERBTemplateTest < Test::Unit::TestCase
|
|
12
12
|
assert_equal Tilt::ERBTemplate, Tilt['test.rhtml']
|
13
13
|
end
|
14
14
|
|
15
|
-
test "
|
15
|
+
test "loading and evaluating templates on #render" do
|
16
16
|
template = Tilt::ERBTemplate.new { |t| "Hello World!" }
|
17
17
|
assert_equal "Hello World!", template.render
|
18
18
|
end
|
@@ -77,9 +77,111 @@ class ERBTemplateTest < Test::Unit::TestCase
|
|
77
77
|
end
|
78
78
|
|
79
79
|
test "shorthand whole line syntax trim mode" do
|
80
|
-
template = Tilt.new('test.erb',
|
80
|
+
template = Tilt.new('test.erb', :trim => '%') { "\n% if true\nhello\n%end\n" }
|
81
81
|
assert_equal "\nhello\n", template.render
|
82
82
|
end
|
83
|
+
|
84
|
+
test "using an instance variable as the outvar" do
|
85
|
+
template = Tilt::ERBTemplate.new(nil, :outvar => '@buf') { "<%= 1 + 1 %>" }
|
86
|
+
scope = Object.new
|
87
|
+
scope.instance_variable_set(:@buf, 'original value')
|
88
|
+
assert_equal '2', template.render(scope)
|
89
|
+
assert_equal 'original value', scope.instance_variable_get(:@buf)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class CompiledERBTemplateTest < Test::Unit::TestCase
|
94
|
+
def teardown
|
95
|
+
GC.start
|
96
|
+
end
|
97
|
+
|
98
|
+
class Scope
|
99
|
+
include Tilt::CompileSite
|
100
|
+
end
|
101
|
+
|
102
|
+
test "compiling template source to a method" do
|
103
|
+
template = Tilt::ERBTemplate.new { |t| "Hello World!" }
|
104
|
+
template.render(Scope.new)
|
105
|
+
method_name = template.send(:compiled_method_name, [].hash)
|
106
|
+
method_name = method_name.to_sym if Symbol === Kernel.methods.first
|
107
|
+
assert Tilt::CompileSite.instance_methods.include?(method_name),
|
108
|
+
"CompileSite.instance_methods.include?(#{method_name.inspect})"
|
109
|
+
assert Scope.new.respond_to?(method_name),
|
110
|
+
"scope.respond_to?(#{method_name.inspect})"
|
111
|
+
end
|
112
|
+
|
113
|
+
test "loading and evaluating templates on #render" do
|
114
|
+
template = Tilt::ERBTemplate.new { |t| "Hello World!" }
|
115
|
+
assert_equal "Hello World!", template.render(Scope.new)
|
116
|
+
assert_equal "Hello World!", template.render(Scope.new)
|
117
|
+
end
|
118
|
+
|
119
|
+
test "passing locals" do
|
120
|
+
template = Tilt::ERBTemplate.new { 'Hey <%= name %>!' }
|
121
|
+
assert_equal "Hey Joe!", template.render(Scope.new, :name => 'Joe')
|
122
|
+
end
|
123
|
+
|
124
|
+
test "evaluating in an object scope" do
|
125
|
+
template = Tilt::ERBTemplate.new { 'Hey <%= @name %>!' }
|
126
|
+
scope = Scope.new
|
127
|
+
scope.instance_variable_set :@name, 'Joe'
|
128
|
+
assert_equal "Hey Joe!", template.render(scope)
|
129
|
+
scope.instance_variable_set :@name, 'Jane'
|
130
|
+
assert_equal "Hey Jane!", template.render(scope)
|
131
|
+
end
|
132
|
+
|
133
|
+
test "passing a block for yield" do
|
134
|
+
template = Tilt::ERBTemplate.new { 'Hey <%= yield %>!' }
|
135
|
+
assert_equal "Hey Joe!", template.render(Scope.new) { 'Joe' }
|
136
|
+
assert_equal "Hey Jane!", template.render(Scope.new) { 'Jane' }
|
137
|
+
end
|
138
|
+
|
139
|
+
test "backtrace file and line reporting without locals" do
|
140
|
+
data = File.read(__FILE__).split("\n__END__\n").last
|
141
|
+
fail unless data[0] == ?<
|
142
|
+
template = Tilt::ERBTemplate.new('test.erb', 11) { data }
|
143
|
+
begin
|
144
|
+
template.render(Scope.new)
|
145
|
+
fail 'should have raised an exception'
|
146
|
+
rescue => boom
|
147
|
+
assert_kind_of NameError, boom
|
148
|
+
line = boom.backtrace.first
|
149
|
+
file, line, meth = line.split(":")
|
150
|
+
assert_equal 'test.erb', file
|
151
|
+
assert_equal '13', line
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
test "backtrace file and line reporting with locals" do
|
156
|
+
data = File.read(__FILE__).split("\n__END__\n").last
|
157
|
+
fail unless data[0] == ?<
|
158
|
+
template = Tilt::ERBTemplate.new('test.erb') { data }
|
159
|
+
begin
|
160
|
+
template.render(Scope.new, :name => 'Joe', :foo => 'bar')
|
161
|
+
fail 'should have raised an exception'
|
162
|
+
rescue => boom
|
163
|
+
assert_kind_of RuntimeError, boom
|
164
|
+
line = boom.backtrace.first
|
165
|
+
file, line, meth = line.split(":")
|
166
|
+
assert_equal 'test.erb', file
|
167
|
+
assert_equal '6', line
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
test "default non-stripping trim mode" do
|
172
|
+
template = Tilt.new('test.erb') { "\n<%= 1 + 1 %>\n" }
|
173
|
+
assert_equal "\n2\n", template.render(Scope.new)
|
174
|
+
end
|
175
|
+
|
176
|
+
test "stripping trim mode" do
|
177
|
+
template = Tilt.new('test.erb', :trim => '-') { "\n<%= 1 + 1 -%>\n" }
|
178
|
+
assert_equal "\n2", template.render(Scope.new)
|
179
|
+
end
|
180
|
+
|
181
|
+
test "shorthand whole line syntax trim mode" do
|
182
|
+
template = Tilt.new('test.erb', :trim => '%') { "\n% if true\nhello\n%end\n" }
|
183
|
+
assert_equal "\nhello\n", template.render(Scope.new)
|
184
|
+
end
|
83
185
|
end
|
84
186
|
|
85
187
|
__END__
|
@@ -9,7 +9,7 @@ begin
|
|
9
9
|
assert_equal Tilt::ErubisTemplate, Tilt['test.html.erubis']
|
10
10
|
end
|
11
11
|
|
12
|
-
test "
|
12
|
+
test "preparing and evaluating templates on #render" do
|
13
13
|
template = Tilt::ErubisTemplate.new { |t| "Hello World!" }
|
14
14
|
assert_equal "Hello World!", template.render
|
15
15
|
end
|
@@ -69,6 +69,14 @@ begin
|
|
69
69
|
scope.instance_variable_set :@name, 'Joe'
|
70
70
|
assert_equal "Hey Joe!", template.render(scope)
|
71
71
|
end
|
72
|
+
|
73
|
+
test "using an instance variable as the outvar" do
|
74
|
+
template = Tilt::ErubisTemplate.new(nil, :outvar => '@buf') { "<%= 1 + 1 %>" }
|
75
|
+
scope = Object.new
|
76
|
+
scope.instance_variable_set(:@buf, 'original value')
|
77
|
+
assert_equal '2', template.render(scope)
|
78
|
+
assert_equal 'original value', scope.instance_variable_get(:@buf)
|
79
|
+
end
|
72
80
|
end
|
73
81
|
rescue LoadError => boom
|
74
82
|
warn "Tilt::ErubisTemplate (disabled)\n"
|
@@ -12,7 +12,7 @@ begin
|
|
12
12
|
assert_equal Tilt::HamlTemplate, Tilt['test.haml']
|
13
13
|
end
|
14
14
|
|
15
|
-
test "
|
15
|
+
test "preparing and evaluating templates on #render" do
|
16
16
|
template = Tilt::HamlTemplate.new { |t| "%p Hello World!" }
|
17
17
|
assert_equal "<p>Hello World!</p>\n", template.render
|
18
18
|
end
|
@@ -66,6 +66,59 @@ begin
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
class CompiledHamlTemplateTest < Test::Unit::TestCase
|
70
|
+
class Scope
|
71
|
+
include Tilt::CompileSite
|
72
|
+
end
|
73
|
+
|
74
|
+
test "passing locals" do
|
75
|
+
template = Tilt::HamlTemplate.new { "%p= 'Hey ' + name + '!'" }
|
76
|
+
assert_equal "<p>Hey Joe!</p>\n", template.render(Scope.new, :name => 'Joe')
|
77
|
+
end
|
78
|
+
|
79
|
+
test "evaluating in an object scope" do
|
80
|
+
template = Tilt::HamlTemplate.new { "%p= 'Hey ' + @name + '!'" }
|
81
|
+
scope = Scope.new
|
82
|
+
scope.instance_variable_set :@name, 'Joe'
|
83
|
+
assert_equal "<p>Hey Joe!</p>\n", template.render(scope)
|
84
|
+
end
|
85
|
+
|
86
|
+
test "passing a block for yield" do
|
87
|
+
template = Tilt::HamlTemplate.new { "%p= 'Hey ' + yield + '!'" }
|
88
|
+
assert_equal "<p>Hey Joe!</p>\n", template.render(Scope.new) { 'Joe' }
|
89
|
+
end
|
90
|
+
|
91
|
+
test "backtrace file and line reporting without locals" do
|
92
|
+
data = File.read(__FILE__).split("\n__END__\n").last
|
93
|
+
fail unless data[0] == ?%
|
94
|
+
template = Tilt::HamlTemplate.new('test.haml', 10) { data }
|
95
|
+
begin
|
96
|
+
template.render(Scope.new)
|
97
|
+
fail 'should have raised an exception'
|
98
|
+
rescue => boom
|
99
|
+
assert_kind_of NameError, boom
|
100
|
+
line = boom.backtrace.first
|
101
|
+
file, line, meth = line.split(":")
|
102
|
+
assert_equal 'test.haml', file
|
103
|
+
assert_equal '12', line
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
test "backtrace file and line reporting with locals" do
|
108
|
+
data = File.read(__FILE__).split("\n__END__\n").last
|
109
|
+
fail unless data[0] == ?%
|
110
|
+
template = Tilt::HamlTemplate.new('test.haml') { data }
|
111
|
+
begin
|
112
|
+
res = template.render(Scope.new, :name => 'Joe', :foo => 'bar')
|
113
|
+
rescue => boom
|
114
|
+
assert_kind_of MockError, boom
|
115
|
+
line = boom.backtrace.first
|
116
|
+
file, line, meth = line.split(":")
|
117
|
+
assert_equal 'test.haml', file
|
118
|
+
assert_equal '5', line
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
69
122
|
rescue LoadError => boom
|
70
123
|
warn "Tilt::HamlTemplate (disabled)\n"
|
71
124
|
end
|
@@ -9,7 +9,7 @@ begin
|
|
9
9
|
assert_equal Tilt::LiquidTemplate, Tilt['test.liquid']
|
10
10
|
end
|
11
11
|
|
12
|
-
test "
|
12
|
+
test "preparing and evaluating templates on #render" do
|
13
13
|
template = Tilt::LiquidTemplate.new { |t| "Hello World!" }
|
14
14
|
assert_equal "Hello World!", template.render
|
15
15
|
end
|
@@ -16,7 +16,7 @@ begin
|
|
16
16
|
assert_equal Tilt::MustacheTemplate, Tilt['test.mustache']
|
17
17
|
end
|
18
18
|
|
19
|
-
test "
|
19
|
+
test "preparing and evaluating templates on #render" do
|
20
20
|
template = Tilt::MustacheTemplate.new { |t| "Hello World!" }
|
21
21
|
assert_equal "Hello World!", template.render
|
22
22
|
end
|
@@ -33,7 +33,6 @@ begin
|
|
33
33
|
|
34
34
|
test "locating views defined at the top-level" do
|
35
35
|
template = Tilt::MustacheTemplate.new('foo.mustache') { "<p>Hey {{foo}}!</p>" }
|
36
|
-
template.compile
|
37
36
|
assert_equal Views::Foo, template.engine
|
38
37
|
end
|
39
38
|
|
@@ -46,7 +45,6 @@ begin
|
|
46
45
|
|
47
46
|
test "locating views defined in a custom namespace" do
|
48
47
|
template = Tilt::MustacheTemplate.new('bizzle.mustache', :namespace => Bar) { "<p>Hello World!</p>" }
|
49
|
-
template.compile
|
50
48
|
assert_equal Bar::Views::Bizzle, template.engine
|
51
49
|
assert_equal "<p>Hello World!</p>", template.render
|
52
50
|
end
|
@@ -54,7 +52,6 @@ begin
|
|
54
52
|
test "locating views in files" do
|
55
53
|
view_path = File.expand_path('../tilt_mustache_views', __FILE__)
|
56
54
|
template = Tilt::MustacheTemplate.new('external.mustache', :view_path => view_path) { "<p>{{hello}}!</p>" }
|
57
|
-
template.compile
|
58
55
|
assert defined?(Views::External), "external.rb should have been required"
|
59
56
|
assert_equal Views::External, template.engine
|
60
57
|
assert_equal "<p>Stached!</p>", template.render
|
@@ -17,20 +17,20 @@ begin
|
|
17
17
|
assert_equal Tilt::RDiscountTemplate, Tilt['test.mkd']
|
18
18
|
end
|
19
19
|
|
20
|
-
test "
|
20
|
+
test "preparing and evaluating templates on #render" do
|
21
21
|
template = Tilt::RDiscountTemplate.new { |t| "# Hello World!" }
|
22
22
|
assert_equal "<h1>Hello World!</h1>\n", template.render
|
23
23
|
end
|
24
24
|
|
25
25
|
test "smartypants when :smart is set" do
|
26
|
-
template = Tilt::RDiscountTemplate.new(
|
26
|
+
template = Tilt::RDiscountTemplate.new(:smart => true) { |t|
|
27
27
|
"OKAY -- 'Smarty Pants'" }
|
28
28
|
assert_equal "<p>OKAY — ‘Smarty Pants’</p>\n",
|
29
29
|
template.render
|
30
30
|
end
|
31
31
|
|
32
32
|
test "stripping HTML when :filter_html is set" do
|
33
|
-
template = Tilt::RDiscountTemplate.new(
|
33
|
+
template = Tilt::RDiscountTemplate.new(:filter_html => true) { |t|
|
34
34
|
"HELLO <blink>WORLD</blink>" }
|
35
35
|
assert_equal "<p>HELLO <blink>WORLD</blink></p>\n", template.render
|
36
36
|
end
|
@@ -9,7 +9,7 @@ begin
|
|
9
9
|
assert_equal Tilt::RDocTemplate, Tilt['test.rdoc']
|
10
10
|
end
|
11
11
|
|
12
|
-
test "
|
12
|
+
test "preparing and evaluating the template with #render" do
|
13
13
|
template = Tilt::RDocTemplate.new { |t| "= Hello World!" }
|
14
14
|
assert_equal "<h1>Hello World!</h1>\n", template.render
|
15
15
|
end
|
@@ -6,7 +6,7 @@ class StringTemplateTest < Test::Unit::TestCase
|
|
6
6
|
assert_equal Tilt::StringTemplate, Tilt['test.str']
|
7
7
|
end
|
8
8
|
|
9
|
-
test "
|
9
|
+
test "loading and evaluating templates on #render" do
|
10
10
|
template = Tilt::StringTemplate.new { |t| "Hello World!" }
|
11
11
|
assert_equal "Hello World!", template.render
|
12
12
|
end
|
@@ -26,6 +26,7 @@ class StringTemplateTest < Test::Unit::TestCase
|
|
26
26
|
test "passing a block for yield" do
|
27
27
|
template = Tilt::StringTemplate.new { 'Hey #{yield}!' }
|
28
28
|
assert_equal "Hey Joe!", template.render { 'Joe' }
|
29
|
+
assert_equal "Hey Moe!", template.render { 'Moe' }
|
29
30
|
end
|
30
31
|
|
31
32
|
test "multiline templates" do
|
@@ -66,6 +67,91 @@ class StringTemplateTest < Test::Unit::TestCase
|
|
66
67
|
end
|
67
68
|
end
|
68
69
|
|
70
|
+
|
71
|
+
class CompiledStringTemplateTest < Test::Unit::TestCase
|
72
|
+
def teardown
|
73
|
+
GC.start
|
74
|
+
end
|
75
|
+
|
76
|
+
class Scope
|
77
|
+
include Tilt::CompileSite
|
78
|
+
end
|
79
|
+
|
80
|
+
test "compiling template source to a method" do
|
81
|
+
template = Tilt::StringTemplate.new { |t| "Hello World!" }
|
82
|
+
template.render(Scope.new)
|
83
|
+
method_name = template.send(:compiled_method_name, [].hash)
|
84
|
+
method_name = method_name.to_sym if Symbol === Kernel.methods.first
|
85
|
+
assert Tilt::CompileSite.instance_methods.include?(method_name),
|
86
|
+
"CompileSite.instance_methods.include?(#{method_name.inspect})"
|
87
|
+
assert Scope.new.respond_to?(method_name),
|
88
|
+
"scope.respond_to?(#{method_name.inspect})"
|
89
|
+
end
|
90
|
+
|
91
|
+
test "loading and evaluating templates on #render" do
|
92
|
+
template = Tilt::StringTemplate.new { |t| "Hello World!" }
|
93
|
+
assert_equal "Hello World!", template.render(Scope.new)
|
94
|
+
end
|
95
|
+
|
96
|
+
test "passing locals" do
|
97
|
+
template = Tilt::StringTemplate.new { 'Hey #{name}!' }
|
98
|
+
assert_equal "Hey Joe!", template.render(Scope.new, :name => 'Joe')
|
99
|
+
assert_equal "Hey Moe!", template.render(Scope.new, :name => 'Moe')
|
100
|
+
end
|
101
|
+
|
102
|
+
test "evaluating in an object scope" do
|
103
|
+
template = Tilt::StringTemplate.new { 'Hey #{@name}!' }
|
104
|
+
scope = Scope.new
|
105
|
+
scope.instance_variable_set :@name, 'Joe'
|
106
|
+
assert_equal "Hey Joe!", template.render(scope)
|
107
|
+
scope.instance_variable_set :@name, 'Moe'
|
108
|
+
assert_equal "Hey Moe!", template.render(scope)
|
109
|
+
end
|
110
|
+
|
111
|
+
test "passing a block for yield" do
|
112
|
+
template = Tilt::StringTemplate.new { 'Hey #{yield}!' }
|
113
|
+
assert_equal "Hey Joe!", template.render(Scope.new) { 'Joe' }
|
114
|
+
assert_equal "Hey Moe!", template.render(Scope.new) { 'Moe' }
|
115
|
+
end
|
116
|
+
|
117
|
+
test "multiline templates" do
|
118
|
+
template = Tilt::StringTemplate.new { "Hello\nWorld!\n" }
|
119
|
+
assert_equal "Hello\nWorld!\n", template.render(Scope.new)
|
120
|
+
end
|
121
|
+
|
122
|
+
test "backtrace file and line reporting without locals" do
|
123
|
+
data = File.read(__FILE__).split("\n__END__\n").last
|
124
|
+
fail unless data[0] == ?<
|
125
|
+
template = Tilt::StringTemplate.new('test.str', 11) { data }
|
126
|
+
begin
|
127
|
+
template.render(Scope.new)
|
128
|
+
fail 'should have raised an exception'
|
129
|
+
rescue => boom
|
130
|
+
assert_kind_of NameError, boom
|
131
|
+
line = boom.backtrace.first
|
132
|
+
file, line, meth = line.split(":")
|
133
|
+
assert_equal 'test.str', file
|
134
|
+
assert_equal '13', line
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
test "backtrace file and line reporting with locals" do
|
139
|
+
data = File.read(__FILE__).split("\n__END__\n").last
|
140
|
+
fail unless data[0] == ?<
|
141
|
+
template = Tilt::StringTemplate.new('test.str') { data }
|
142
|
+
begin
|
143
|
+
template.render(Scope.new, :name => 'Joe', :foo => 'bar')
|
144
|
+
fail 'should have raised an exception'
|
145
|
+
rescue => boom
|
146
|
+
assert_kind_of RuntimeError, boom
|
147
|
+
line = boom.backtrace.first
|
148
|
+
file, line, meth = line.split(":")
|
149
|
+
assert_equal 'test.str', file
|
150
|
+
assert_equal '6', line
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
69
155
|
__END__
|
70
156
|
<html>
|
71
157
|
<body>
|
data/test/tilt_template_test.rb
CHANGED
@@ -2,44 +2,50 @@ require 'contest'
|
|
2
2
|
require 'tilt'
|
3
3
|
|
4
4
|
class TiltTemplateTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
class MockTemplate < Tilt::Template
|
7
|
+
def prepare
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
5
11
|
test "needs a file or block" do
|
6
12
|
assert_raise(ArgumentError) { Tilt::Template.new }
|
7
13
|
end
|
8
14
|
|
9
15
|
test "initializing with a file" do
|
10
|
-
inst =
|
16
|
+
inst = MockTemplate.new('foo.erb') {}
|
11
17
|
assert_equal 'foo.erb', inst.file
|
12
18
|
end
|
13
19
|
|
14
20
|
test "initializing with a file and line" do
|
15
|
-
inst =
|
21
|
+
inst = MockTemplate.new('foo.erb', 55) {}
|
16
22
|
assert_equal 'foo.erb', inst.file
|
17
23
|
assert_equal 55, inst.line
|
18
24
|
end
|
19
25
|
|
20
26
|
test "uses correct eval_file" do
|
21
|
-
inst =
|
27
|
+
inst = MockTemplate.new('foo.erb', 55) {}
|
22
28
|
assert_equal 'foo.erb', inst.eval_file
|
23
29
|
end
|
24
30
|
|
25
31
|
test "uses a default filename for #eval_file when no file provided" do
|
26
|
-
inst =
|
32
|
+
inst = MockTemplate.new { 'Hi' }
|
27
33
|
assert_not_nil inst.eval_file
|
28
34
|
assert !inst.eval_file.include?("\n")
|
29
35
|
end
|
30
36
|
|
31
37
|
test "calculating template's #basename" do
|
32
|
-
inst =
|
38
|
+
inst = MockTemplate.new('/tmp/templates/foo.html.erb') {}
|
33
39
|
assert_equal 'foo.html.erb', inst.basename
|
34
40
|
end
|
35
41
|
|
36
42
|
test "calculating the template's #name" do
|
37
|
-
inst =
|
43
|
+
inst = MockTemplate.new('/tmp/templates/foo.html.erb') {}
|
38
44
|
assert_equal 'foo', inst.name
|
39
45
|
end
|
40
46
|
|
41
47
|
test "initializing with a data loading block" do
|
42
|
-
|
48
|
+
MockTemplate.new { |template| "Hello World!" }
|
43
49
|
end
|
44
50
|
|
45
51
|
class InitializingMockTemplate < Tilt::Template
|
@@ -52,7 +58,7 @@ class TiltTemplateTest < Test::Unit::TestCase
|
|
52
58
|
@@initialized_count += 1
|
53
59
|
end
|
54
60
|
|
55
|
-
def
|
61
|
+
def prepare
|
56
62
|
end
|
57
63
|
end
|
58
64
|
|
@@ -68,43 +74,42 @@ class TiltTemplateTest < Test::Unit::TestCase
|
|
68
74
|
assert_equal 1, InitializingMockTemplate.initialized_count
|
69
75
|
end
|
70
76
|
|
71
|
-
class
|
77
|
+
class PreparingMockTemplate < Tilt::Template
|
72
78
|
include Test::Unit::Assertions
|
73
|
-
def
|
79
|
+
def prepare
|
74
80
|
assert !data.nil?
|
75
|
-
@
|
81
|
+
@prepared = true
|
76
82
|
end
|
77
|
-
def
|
83
|
+
def prepared? ; @prepared ; end
|
78
84
|
end
|
79
85
|
|
80
|
-
test "raises NotImplementedError when #
|
81
|
-
|
82
|
-
assert_raise(NotImplementedError) { inst.render }
|
86
|
+
test "raises NotImplementedError when #prepare not defined" do
|
87
|
+
assert_raise(NotImplementedError) { Tilt::Template.new { |template| "Hello World!" } }
|
83
88
|
end
|
84
89
|
|
85
90
|
test "raises NotImplementedError when #evaluate or #template_source not defined" do
|
86
|
-
inst =
|
91
|
+
inst = PreparingMockTemplate.new { |t| "Hello World!" }
|
87
92
|
assert_raise(NotImplementedError) { inst.render }
|
88
|
-
assert inst.
|
93
|
+
assert inst.prepared?
|
89
94
|
end
|
90
95
|
|
91
|
-
class SimpleMockTemplate <
|
96
|
+
class SimpleMockTemplate < PreparingMockTemplate
|
92
97
|
include Test::Unit::Assertions
|
93
98
|
def evaluate(scope, locals, &block)
|
94
|
-
assert
|
99
|
+
assert prepared?
|
95
100
|
assert !scope.nil?
|
96
101
|
assert !locals.nil?
|
97
102
|
"<em>#{@data}</em>"
|
98
103
|
end
|
99
104
|
end
|
100
105
|
|
101
|
-
test "
|
106
|
+
test "prepares and evaluates the template on #render" do
|
102
107
|
inst = SimpleMockTemplate.new { |t| "Hello World!" }
|
103
108
|
assert_equal "<em>Hello World!</em>", inst.render
|
104
|
-
assert inst.
|
109
|
+
assert inst.prepared?
|
105
110
|
end
|
106
111
|
|
107
|
-
class SourceGeneratingMockTemplate <
|
112
|
+
class SourceGeneratingMockTemplate < PreparingMockTemplate
|
108
113
|
def template_source
|
109
114
|
"foo = [] ; foo << %Q{#{data}} ; foo.join"
|
110
115
|
end
|
@@ -113,7 +118,7 @@ class TiltTemplateTest < Test::Unit::TestCase
|
|
113
118
|
test "template_source with locals" do
|
114
119
|
inst = SourceGeneratingMockTemplate.new { |t| 'Hey #{name}!' }
|
115
120
|
assert_equal "Hey Joe!", inst.render(Object.new, :name => 'Joe')
|
116
|
-
assert inst.
|
121
|
+
assert inst.prepared?
|
117
122
|
end
|
118
123
|
|
119
124
|
class Person
|
data/tilt.gemspec
CHANGED
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'tilt'
|
6
|
-
s.version = '0.
|
7
|
-
s.date = '2010-
|
6
|
+
s.version = '0.7'
|
7
|
+
s.date = '2010-03-04'
|
8
8
|
|
9
9
|
s.description = "Generic interface to multiple Ruby template engines"
|
10
10
|
s.summary = s.description
|
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
test/tilt_buildertemplate_test.rb
|
24
24
|
test/tilt_cache_test.rb
|
25
25
|
test/tilt_coffeetemplate_test.rb
|
26
|
+
test/tilt_compilesite_test.rb
|
26
27
|
test/tilt_erbtemplate_test.rb
|
27
28
|
test/tilt_erubistemplate_test.rb
|
28
29
|
test/tilt_hamltemplate_test.rb
|
@@ -50,6 +51,7 @@ Gem::Specification.new do |s|
|
|
50
51
|
s.add_development_dependency 'rdiscount'
|
51
52
|
s.add_development_dependency 'liquid'
|
52
53
|
s.add_development_dependency 'less'
|
54
|
+
s.add_development_dependency 'coffee-script'
|
53
55
|
|
54
56
|
s.extra_rdoc_files = %w[COPYING]
|
55
57
|
|
metadata
CHANGED
@@ -4,8 +4,8 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
version: "0.
|
7
|
+
- 7
|
8
|
+
version: "0.7"
|
9
9
|
platform: ruby
|
10
10
|
authors:
|
11
11
|
- Ryan Tomayko
|
@@ -13,7 +13,7 @@ autorequire:
|
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
15
|
|
16
|
-
date: 2010-
|
16
|
+
date: 2010-03-04 00:00:00 -08:00
|
17
17
|
default_executable:
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
@@ -112,6 +112,18 @@ dependencies:
|
|
112
112
|
version: "0"
|
113
113
|
type: :development
|
114
114
|
version_requirements: *id008
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: coffee-script
|
117
|
+
prerelease: false
|
118
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
segments:
|
123
|
+
- 0
|
124
|
+
version: "0"
|
125
|
+
type: :development
|
126
|
+
version_requirements: *id009
|
115
127
|
description: Generic interface to multiple Ruby template engines
|
116
128
|
email: r@tomayko.com
|
117
129
|
executables: []
|
@@ -130,6 +142,7 @@ files:
|
|
130
142
|
- test/tilt_buildertemplate_test.rb
|
131
143
|
- test/tilt_cache_test.rb
|
132
144
|
- test/tilt_coffeetemplate_test.rb
|
145
|
+
- test/tilt_compilesite_test.rb
|
133
146
|
- test/tilt_erbtemplate_test.rb
|
134
147
|
- test/tilt_erubistemplate_test.rb
|
135
148
|
- test/tilt_hamltemplate_test.rb
|