tilt 0.6 → 0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|