tilt 0.7 → 1.1
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/COPYING +1 -1
- data/README.md +50 -4
- data/Rakefile +7 -24
- data/TEMPLATES.md +71 -55
- data/bin/tilt +45 -16
- data/lib/tilt.rb +374 -165
- data/test/contest.rb +68 -0
- data/test/markaby/locals.mab +1 -0
- data/test/markaby/markaby.mab +1 -0
- data/test/markaby/markaby_other_static.mab +1 -0
- data/test/markaby/render_twice.mab +1 -0
- data/test/markaby/scope.mab +1 -0
- data/test/markaby/yielding.mab +2 -0
- data/test/tilt_cache_test.rb +2 -3
- data/test/tilt_coffeescripttemplate_test.rb +25 -0
- data/test/tilt_compilesite_test.rb +28 -4
- data/test/tilt_erbtemplate_test.rb +18 -1
- data/test/tilt_erubistemplate_test.rb +43 -0
- data/test/tilt_hamltemplate_test.rb +11 -0
- data/test/tilt_markaby_test.rb +73 -0
- data/test/tilt_nokogiritemplate_test.rb +54 -0
- data/test/tilt_radiustemplate_test.rb +70 -0
- data/test/tilt_sasstemplate_test.rb +13 -2
- data/test/tilt_stringtemplate_test.rb +1 -1
- data/test/tilt_template_test.rb +18 -1
- data/test/tilt_test.rb +9 -1
- data/tilt.gemspec +21 -8
- metadata +99 -20
- data/test/tilt_coffeetemplate_test.rb +0 -20
- data/test/tilt_mustache_views/external.rb +0 -9
- data/test/tilt_mustachetemplate_test.rb +0 -70
data/lib/tilt.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
require 'digest/md5'
|
|
2
|
+
|
|
1
3
|
module Tilt
|
|
2
|
-
VERSION = '
|
|
4
|
+
VERSION = '1.1'
|
|
3
5
|
|
|
4
6
|
@template_mappings = {}
|
|
5
7
|
|
|
@@ -14,6 +16,11 @@ module Tilt
|
|
|
14
16
|
mappings[ext.downcase] = template_class
|
|
15
17
|
end
|
|
16
18
|
|
|
19
|
+
# Returns true when a template exists on an exact match of the provided file extension
|
|
20
|
+
def self.registered?(ext)
|
|
21
|
+
mappings.key?(ext.downcase)
|
|
22
|
+
end
|
|
23
|
+
|
|
17
24
|
# Create a new template for the given file using the file's extension
|
|
18
25
|
# to determine the the template mapping.
|
|
19
26
|
def self.new(file, line=nil, options={}, &block)
|
|
@@ -27,20 +34,12 @@ module Tilt
|
|
|
27
34
|
# Lookup a template class for the given filename or file
|
|
28
35
|
# extension. Return nil when no implementation is found.
|
|
29
36
|
def self.[](file)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
else
|
|
35
|
-
while !pattern.empty?
|
|
36
|
-
if @template_mappings.key?(pattern)
|
|
37
|
-
return @template_mappings[pattern]
|
|
38
|
-
else
|
|
39
|
-
pattern = pattern.sub(/^[^.]*\.?/, '')
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
nil
|
|
37
|
+
pattern = file.to_s.downcase
|
|
38
|
+
unless registered?(pattern)
|
|
39
|
+
pattern = File.basename(pattern)
|
|
40
|
+
pattern.sub!(/^[^.]*\.?/, '') until (pattern.empty? || registered?(pattern))
|
|
43
41
|
end
|
|
42
|
+
@template_mappings[pattern]
|
|
44
43
|
end
|
|
45
44
|
|
|
46
45
|
# Mixin allowing template compilation on scope objects.
|
|
@@ -60,7 +59,7 @@ module Tilt
|
|
|
60
59
|
end
|
|
61
60
|
|
|
62
61
|
# Base class for template implementations. Subclasses must implement
|
|
63
|
-
# the #prepare method and one of the #evaluate or #
|
|
62
|
+
# the #prepare method and one of the #evaluate or #precompiled_template
|
|
64
63
|
# methods.
|
|
65
64
|
class Template
|
|
66
65
|
# Template source; loaded from a file or given directly.
|
|
@@ -98,7 +97,7 @@ module Tilt
|
|
|
98
97
|
case
|
|
99
98
|
when arg.respond_to?(:to_str) ; @file = arg.to_str
|
|
100
99
|
when arg.respond_to?(:to_int) ; @line = arg.to_int
|
|
101
|
-
when arg.respond_to?(:to_hash) ; @options = arg.to_hash
|
|
100
|
+
when arg.respond_to?(:to_hash) ; @options = arg.to_hash.dup
|
|
102
101
|
else raise TypeError
|
|
103
102
|
end
|
|
104
103
|
end
|
|
@@ -113,8 +112,8 @@ module Tilt
|
|
|
113
112
|
end
|
|
114
113
|
|
|
115
114
|
# used to generate unique method names for template compilation
|
|
116
|
-
stamp = (Time.now.to_f * 10000).to_i
|
|
117
|
-
@
|
|
115
|
+
@stamp = (Time.now.to_f * 10000).to_i
|
|
116
|
+
@compiled_method_names = {}
|
|
118
117
|
|
|
119
118
|
# load template data and prepare
|
|
120
119
|
@reader = block || lambda { |t| File.read(@file) }
|
|
@@ -151,6 +150,16 @@ module Tilt
|
|
|
151
150
|
def initialize_engine
|
|
152
151
|
end
|
|
153
152
|
|
|
153
|
+
# Like Kernel::require but issues a warning urging a manual require when
|
|
154
|
+
# running under a threaded environment.
|
|
155
|
+
def require_template_library(name)
|
|
156
|
+
if Thread.list.size > 1
|
|
157
|
+
warn "WARN: tilt autoloading '#{name}' in a non thread-safe way; " +
|
|
158
|
+
"explicit require '#{name}' suggested."
|
|
159
|
+
end
|
|
160
|
+
require name
|
|
161
|
+
end
|
|
162
|
+
|
|
154
163
|
# Do whatever preparation is necessary to setup the underlying template
|
|
155
164
|
# engine. Called immediately after template data is loaded. Instance
|
|
156
165
|
# variables set in this method are available when #evaluate is called.
|
|
@@ -175,54 +184,116 @@ module Tilt
|
|
|
175
184
|
# specified and with support for yielding to the block.
|
|
176
185
|
def evaluate(scope, locals, &block)
|
|
177
186
|
if scope.respond_to?(:__tilt__)
|
|
178
|
-
method_name = compiled_method_name(locals.keys
|
|
187
|
+
method_name = compiled_method_name(locals.keys)
|
|
179
188
|
if scope.respond_to?(method_name)
|
|
180
|
-
|
|
181
|
-
scope.send method_name, locals, &block
|
|
189
|
+
scope.send(method_name, locals, &block)
|
|
182
190
|
else
|
|
183
|
-
# compile first and then run
|
|
184
191
|
compile_template_method(method_name, locals)
|
|
185
|
-
scope.send
|
|
192
|
+
scope.send(method_name, locals, &block)
|
|
186
193
|
end
|
|
187
194
|
else
|
|
188
|
-
|
|
189
|
-
source = [source, template_source].join("\n")
|
|
190
|
-
scope.instance_eval source, eval_file, line - offset
|
|
195
|
+
evaluate_source(scope, locals, &block)
|
|
191
196
|
end
|
|
192
197
|
end
|
|
193
198
|
|
|
194
|
-
#
|
|
195
|
-
#
|
|
196
|
-
#
|
|
197
|
-
#
|
|
198
|
-
|
|
199
|
+
# Generates all template source by combining the preamble, template, and
|
|
200
|
+
# postamble and returns a two-tuple of the form: [source, offset], where
|
|
201
|
+
# source is the string containing (Ruby) source code for the template and
|
|
202
|
+
# offset is the integer line offset where line reporting should begin.
|
|
203
|
+
#
|
|
204
|
+
# Template subclasses may override this method when they need complete
|
|
205
|
+
# control over source generation or want to adjust the default line
|
|
206
|
+
# offset. In most cases, overriding the #precompiled_template method is
|
|
207
|
+
# easier and more appropriate.
|
|
208
|
+
def precompiled(locals)
|
|
209
|
+
preamble = precompiled_preamble(locals)
|
|
210
|
+
parts = [
|
|
211
|
+
preamble,
|
|
212
|
+
precompiled_template(locals),
|
|
213
|
+
precompiled_postamble(locals)
|
|
214
|
+
]
|
|
215
|
+
[parts.join("\n"), preamble.count("\n") + 1]
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# A string containing the (Ruby) source code for the template. The
|
|
219
|
+
# default Template#evaluate implementation requires either this method
|
|
220
|
+
# or the #precompiled method be overridden. When defined, the base
|
|
221
|
+
# Template guarantees correct file/line handling, locals support, custom
|
|
222
|
+
# scopes, and support for template compilation when the scope object
|
|
223
|
+
# allows it.
|
|
224
|
+
def precompiled_template(locals)
|
|
199
225
|
raise NotImplementedError
|
|
200
226
|
end
|
|
201
227
|
|
|
228
|
+
# Generates preamble code for initializing template state, and performing
|
|
229
|
+
# locals assignment. The default implementation performs locals
|
|
230
|
+
# assignment only. Lines included in the preamble are subtracted from the
|
|
231
|
+
# source line offset, so adding code to the preamble does not effect line
|
|
232
|
+
# reporting in Kernel::caller and backtraces.
|
|
233
|
+
def precompiled_preamble(locals)
|
|
234
|
+
locals.map { |k,v| "#{k} = locals[:#{k}]" }.join("\n")
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Generates postamble code for the precompiled template source. The
|
|
238
|
+
# string returned from this method is appended to the precompiled
|
|
239
|
+
# template source.
|
|
240
|
+
def precompiled_postamble(locals)
|
|
241
|
+
''
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# The unique compiled method name for the locals keys provided.
|
|
245
|
+
def compiled_method_name(locals_keys)
|
|
246
|
+
@compiled_method_names[locals_keys] ||=
|
|
247
|
+
generate_compiled_method_name(locals_keys)
|
|
248
|
+
end
|
|
249
|
+
|
|
202
250
|
private
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
source
|
|
206
|
-
|
|
251
|
+
# Evaluate the template source in the context of the scope object.
|
|
252
|
+
def evaluate_source(scope, locals, &block)
|
|
253
|
+
source, offset = precompiled(locals)
|
|
254
|
+
scope.instance_eval(source, eval_file, line - offset)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# JRuby doesn't allow Object#instance_eval to yield to the block it's
|
|
258
|
+
# closed over. This is by design and (ostensibly) something that will
|
|
259
|
+
# change in MRI, though no current MRI version tested (1.8.6 - 1.9.2)
|
|
260
|
+
# exhibits the behavior. More info here:
|
|
261
|
+
#
|
|
262
|
+
# http://jira.codehaus.org/browse/JRUBY-2599
|
|
263
|
+
#
|
|
264
|
+
# Additionally, JRuby's eval line reporting is off by one compared to
|
|
265
|
+
# all MRI versions tested.
|
|
266
|
+
#
|
|
267
|
+
# We redefine evaluate_source to work around both issues.
|
|
268
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
|
269
|
+
undef evaluate_source
|
|
270
|
+
def evaluate_source(scope, locals, &block)
|
|
271
|
+
source, offset = precompiled(locals)
|
|
272
|
+
file, lineno = eval_file, (line - offset) - 1
|
|
273
|
+
scope.instance_eval { Kernel::eval(source, binding, file, lineno) }
|
|
274
|
+
end
|
|
207
275
|
end
|
|
208
276
|
|
|
209
|
-
def
|
|
210
|
-
|
|
277
|
+
def generate_compiled_method_name(locals_keys)
|
|
278
|
+
parts = [object_id, @stamp] + locals_keys.map { |k| k.to_s }.sort
|
|
279
|
+
digest = Digest::MD5.hexdigest(parts.join(':'))
|
|
280
|
+
"__tilt_#{digest}"
|
|
211
281
|
end
|
|
212
282
|
|
|
213
283
|
def compile_template_method(method_name, locals)
|
|
214
|
-
source, offset =
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
# add the new method
|
|
219
|
-
CompileSite.module_eval <<-RUBY, eval_file, line - offset
|
|
284
|
+
source, offset = precompiled(locals)
|
|
285
|
+
offset += 5
|
|
286
|
+
CompileSite.class_eval <<-RUBY, eval_file, line - offset
|
|
220
287
|
def #{method_name}(locals)
|
|
221
|
-
|
|
288
|
+
Thread.current[:tilt_vars] = [self, locals]
|
|
289
|
+
class << self
|
|
290
|
+
this, locals = Thread.current[:tilt_vars]
|
|
291
|
+
this.instance_eval do
|
|
292
|
+
#{source}
|
|
293
|
+
end
|
|
294
|
+
end
|
|
222
295
|
end
|
|
223
296
|
RUBY
|
|
224
|
-
|
|
225
|
-
# setup a finalizer to remove the newly added method
|
|
226
297
|
ObjectSpace.define_finalizer self,
|
|
227
298
|
Template.compiled_template_method_remover(CompileSite, method_name)
|
|
228
299
|
end
|
|
@@ -241,12 +312,25 @@ module Tilt
|
|
|
241
312
|
end
|
|
242
313
|
end
|
|
243
314
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
315
|
+
# Special case Ruby 1.9.1's broken yield.
|
|
316
|
+
#
|
|
317
|
+
# http://github.com/rtomayko/tilt/commit/20c01a5
|
|
318
|
+
# http://redmine.ruby-lang.org/issues/show/3601
|
|
319
|
+
#
|
|
320
|
+
# Remove when 1.9.2 dominates 1.9.1 installs in the wild.
|
|
321
|
+
if RUBY_VERSION =~ /^1.9.1/
|
|
322
|
+
undef compile_template_method
|
|
323
|
+
def compile_template_method(method_name, locals)
|
|
324
|
+
source, offset = precompiled(locals)
|
|
325
|
+
offset += 1
|
|
326
|
+
CompileSite.module_eval <<-RUBY, eval_file, line - offset
|
|
327
|
+
def #{method_name}(locals)
|
|
328
|
+
#{source}
|
|
329
|
+
end
|
|
330
|
+
RUBY
|
|
331
|
+
ObjectSpace.define_finalizer self,
|
|
332
|
+
Template.compiled_template_method_remover(CompileSite, method_name)
|
|
248
333
|
end
|
|
249
|
-
require name
|
|
250
334
|
end
|
|
251
335
|
end
|
|
252
336
|
|
|
@@ -282,7 +366,7 @@ module Tilt
|
|
|
282
366
|
@code = "%Q{#{data}}"
|
|
283
367
|
end
|
|
284
368
|
|
|
285
|
-
def
|
|
369
|
+
def precompiled_template(locals)
|
|
286
370
|
@code
|
|
287
371
|
end
|
|
288
372
|
end
|
|
@@ -292,72 +376,99 @@ module Tilt
|
|
|
292
376
|
# ERB template implementation. See:
|
|
293
377
|
# http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html
|
|
294
378
|
class ERBTemplate < Template
|
|
379
|
+
@@default_output_variable = '_erbout'
|
|
380
|
+
|
|
381
|
+
def self.default_output_variable
|
|
382
|
+
@@default_output_variable
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def self.default_output_variable=(name)
|
|
386
|
+
@@default_output_variable = name
|
|
387
|
+
end
|
|
388
|
+
|
|
295
389
|
def initialize_engine
|
|
296
|
-
|
|
390
|
+
return if defined? ::ERB
|
|
391
|
+
require_template_library 'erb'
|
|
297
392
|
end
|
|
298
393
|
|
|
299
394
|
def prepare
|
|
300
|
-
@outvar =
|
|
395
|
+
@outvar = options[:outvar] || self.class.default_output_variable
|
|
301
396
|
@engine = ::ERB.new(data, options[:safe], options[:trim], @outvar)
|
|
302
397
|
end
|
|
303
398
|
|
|
304
|
-
def
|
|
305
|
-
@engine.src
|
|
399
|
+
def precompiled_template(locals)
|
|
400
|
+
source = @engine.src
|
|
401
|
+
source
|
|
306
402
|
end
|
|
307
403
|
|
|
308
|
-
def
|
|
309
|
-
|
|
404
|
+
def precompiled_preamble(locals)
|
|
405
|
+
<<-RUBY
|
|
406
|
+
begin
|
|
407
|
+
__original_outvar = #{@outvar} if defined?(#{@outvar})
|
|
408
|
+
#{super}
|
|
409
|
+
RUBY
|
|
310
410
|
end
|
|
311
411
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
output = yield
|
|
320
|
-
scope.instance_variable_set(@outvar, previous)
|
|
321
|
-
output
|
|
322
|
-
else
|
|
323
|
-
yield
|
|
324
|
-
end
|
|
412
|
+
def precompiled_postamble(locals)
|
|
413
|
+
<<-RUBY
|
|
414
|
+
#{super}
|
|
415
|
+
ensure
|
|
416
|
+
#{@outvar} = __original_outvar
|
|
417
|
+
end
|
|
418
|
+
RUBY
|
|
325
419
|
end
|
|
326
420
|
|
|
327
421
|
# ERB generates a line to specify the character coding of the generated
|
|
328
422
|
# source in 1.9. Account for this in the line offset.
|
|
329
423
|
if RUBY_VERSION >= '1.9.0'
|
|
330
|
-
def
|
|
424
|
+
def precompiled(locals)
|
|
331
425
|
source, offset = super
|
|
332
426
|
[source, offset + 1]
|
|
333
427
|
end
|
|
334
428
|
end
|
|
335
429
|
end
|
|
430
|
+
|
|
336
431
|
%w[erb rhtml].each { |ext| register ext, ERBTemplate }
|
|
337
432
|
|
|
338
433
|
|
|
339
434
|
# Erubis template implementation. See:
|
|
340
435
|
# http://www.kuwata-lab.com/erubis/
|
|
436
|
+
#
|
|
437
|
+
# ErubisTemplate supports the following additional options, which are not
|
|
438
|
+
# passed down to the Erubis engine:
|
|
439
|
+
#
|
|
440
|
+
# :engine_class allows you to specify a custom engine class to use
|
|
441
|
+
# instead of the default (which is ::Erubis::Eruby).
|
|
442
|
+
#
|
|
443
|
+
# :escape_html when true, ::Erubis::EscapedEruby will be used as
|
|
444
|
+
# the engine class instead of the default. All content
|
|
445
|
+
# within <%= %> blocks will be automatically html escaped.
|
|
341
446
|
class ErubisTemplate < ERBTemplate
|
|
342
447
|
def initialize_engine
|
|
343
|
-
|
|
448
|
+
return if defined? ::Erubis
|
|
449
|
+
require_template_library 'erubis'
|
|
344
450
|
end
|
|
345
451
|
|
|
346
452
|
def prepare
|
|
347
453
|
@options.merge!(:preamble => false, :postamble => false)
|
|
348
|
-
@outvar =
|
|
349
|
-
|
|
454
|
+
@outvar = options.delete(:outvar) || self.class.default_output_variable
|
|
455
|
+
engine_class = options.delete(:engine_class)
|
|
456
|
+
engine_class = ::Erubis::EscapedEruby if options.delete(:escape_html)
|
|
457
|
+
@engine = (engine_class || ::Erubis::Eruby).new(data, options)
|
|
350
458
|
end
|
|
351
459
|
|
|
352
|
-
def
|
|
353
|
-
["#{@outvar} = _buf = ''"
|
|
460
|
+
def precompiled_preamble(locals)
|
|
461
|
+
[super, "#{@outvar} = _buf = ''"].join("\n")
|
|
354
462
|
end
|
|
355
463
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
464
|
+
def precompiled_postamble(locals)
|
|
465
|
+
["_buf", super].join("\n")
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
# Erubis doesn't have ERB's line-off-by-one under 1.9 problem.
|
|
469
|
+
# Override and adjust back.
|
|
359
470
|
if RUBY_VERSION >= '1.9.0'
|
|
360
|
-
def
|
|
471
|
+
def precompiled(locals)
|
|
361
472
|
source, offset = super
|
|
362
473
|
[source, offset - 1]
|
|
363
474
|
end
|
|
@@ -370,26 +481,48 @@ module Tilt
|
|
|
370
481
|
# http://haml.hamptoncatlin.com/
|
|
371
482
|
class HamlTemplate < Template
|
|
372
483
|
def initialize_engine
|
|
373
|
-
|
|
484
|
+
return if defined? ::Haml::Engine
|
|
485
|
+
require_template_library 'haml'
|
|
374
486
|
end
|
|
375
487
|
|
|
376
488
|
def prepare
|
|
377
|
-
|
|
489
|
+
options = @options.merge(:filename => eval_file, :line => line)
|
|
490
|
+
@engine = ::Haml::Engine.new(data, options)
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
def evaluate(scope, locals, &block)
|
|
494
|
+
if @engine.respond_to?(:precompiled_method_return_value, true)
|
|
495
|
+
super
|
|
496
|
+
else
|
|
497
|
+
@engine.render(scope, locals, &block)
|
|
498
|
+
end
|
|
378
499
|
end
|
|
379
500
|
|
|
380
501
|
# Precompiled Haml source. Taken from the precompiled_with_ambles
|
|
381
502
|
# method in Haml::Precompiler:
|
|
382
503
|
# http://github.com/nex3/haml/blob/master/lib/haml/precompiler.rb#L111-126
|
|
383
|
-
def
|
|
504
|
+
def precompiled_template(locals)
|
|
505
|
+
@engine.precompiled
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def precompiled_preamble(locals)
|
|
509
|
+
local_assigns = super
|
|
384
510
|
@engine.instance_eval do
|
|
385
511
|
<<-RUBY
|
|
386
|
-
_haml_locals = locals
|
|
387
512
|
begin
|
|
388
513
|
extend Haml::Helpers
|
|
389
514
|
_hamlout = @haml_buffer = Haml::Buffer.new(@haml_buffer, #{options_for_buffer.inspect})
|
|
390
515
|
_erbout = _hamlout.buffer
|
|
391
516
|
__in_erb_template = true
|
|
392
|
-
|
|
517
|
+
_haml_locals = locals
|
|
518
|
+
#{local_assigns}
|
|
519
|
+
RUBY
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def precompiled_postamble(locals)
|
|
524
|
+
@engine.instance_eval do
|
|
525
|
+
<<-RUBY
|
|
393
526
|
#{precompiled_method_return_value}
|
|
394
527
|
ensure
|
|
395
528
|
@haml_buffer = @haml_buffer.upper
|
|
@@ -397,16 +530,6 @@ module Tilt
|
|
|
397
530
|
RUBY
|
|
398
531
|
end
|
|
399
532
|
end
|
|
400
|
-
|
|
401
|
-
private
|
|
402
|
-
def local_assignment_code(locals)
|
|
403
|
-
source, offset = super
|
|
404
|
-
[source, offset + 6]
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
def haml_options
|
|
408
|
-
options.merge(:filename => eval_file, :line => line)
|
|
409
|
-
end
|
|
410
533
|
end
|
|
411
534
|
register 'haml', HamlTemplate
|
|
412
535
|
|
|
@@ -417,7 +540,8 @@ module Tilt
|
|
|
417
540
|
# Sass templates do not support object scopes, locals, or yield.
|
|
418
541
|
class SassTemplate < Template
|
|
419
542
|
def initialize_engine
|
|
420
|
-
|
|
543
|
+
return if defined? ::Sass::Engine
|
|
544
|
+
require_template_library 'sass'
|
|
421
545
|
end
|
|
422
546
|
|
|
423
547
|
def prepare
|
|
@@ -430,11 +554,19 @@ module Tilt
|
|
|
430
554
|
|
|
431
555
|
private
|
|
432
556
|
def sass_options
|
|
433
|
-
options.merge(:filename => eval_file, :line => line)
|
|
557
|
+
options.merge(:filename => eval_file, :line => line, :syntax => :sass)
|
|
434
558
|
end
|
|
435
559
|
end
|
|
436
560
|
register 'sass', SassTemplate
|
|
437
561
|
|
|
562
|
+
# Sass's new .scss type template implementation.
|
|
563
|
+
class ScssTemplate < SassTemplate
|
|
564
|
+
private
|
|
565
|
+
def sass_options
|
|
566
|
+
options.merge(:filename => eval_file, :line => line, :syntax => :scss)
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
register 'scss', ScssTemplate
|
|
438
570
|
|
|
439
571
|
# Lessscss template implementation. See:
|
|
440
572
|
# http://lesscss.org/
|
|
@@ -442,7 +574,8 @@ module Tilt
|
|
|
442
574
|
# Less templates do not support object scopes, locals, or yield.
|
|
443
575
|
class LessTemplate < Template
|
|
444
576
|
def initialize_engine
|
|
445
|
-
|
|
577
|
+
return if defined? ::Less::Engine
|
|
578
|
+
require_template_library 'less'
|
|
446
579
|
end
|
|
447
580
|
|
|
448
581
|
def prepare
|
|
@@ -456,11 +589,71 @@ module Tilt
|
|
|
456
589
|
register 'less', LessTemplate
|
|
457
590
|
|
|
458
591
|
|
|
592
|
+
# CoffeeScript template implementation. See:
|
|
593
|
+
# http://coffeescript.org/
|
|
594
|
+
#
|
|
595
|
+
# CoffeeScript templates do not support object scopes, locals, or yield.
|
|
596
|
+
class CoffeeScriptTemplate < Template
|
|
597
|
+
@@default_no_wrap = false
|
|
598
|
+
|
|
599
|
+
def self.default_no_wrap
|
|
600
|
+
@@default_no_wrap
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
def self.default_no_wrap=(value)
|
|
604
|
+
@@default_no_wrap = value
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
def initialize_engine
|
|
608
|
+
return if defined? ::CoffeeScript
|
|
609
|
+
require_template_library 'coffee_script'
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
def prepare
|
|
613
|
+
@no_wrap = options.key?(:no_wrap) ? options[:no_wrap] :
|
|
614
|
+
self.class.default_no_wrap
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
def evaluate(scope, locals, &block)
|
|
618
|
+
@output ||= CoffeeScript.compile(data, :no_wrap => @no_wrap)
|
|
619
|
+
end
|
|
620
|
+
end
|
|
621
|
+
register 'coffee', CoffeeScriptTemplate
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
# Nokogiri template implementation. See:
|
|
625
|
+
# http://nokogiri.org/
|
|
626
|
+
class NokogiriTemplate < Template
|
|
627
|
+
def initialize_engine
|
|
628
|
+
return if defined?(::Nokogiri)
|
|
629
|
+
require_template_library 'nokogiri'
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
def prepare; end
|
|
633
|
+
|
|
634
|
+
def evaluate(scope, locals, &block)
|
|
635
|
+
xml = ::Nokogiri::XML::Builder.new
|
|
636
|
+
if data.respond_to?(:to_str)
|
|
637
|
+
locals[:xml] = xml
|
|
638
|
+
super(scope, locals, &block)
|
|
639
|
+
elsif data.kind_of?(Proc)
|
|
640
|
+
data.call(xml)
|
|
641
|
+
end
|
|
642
|
+
xml.to_xml
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
def precompiled_template(locals)
|
|
646
|
+
data.to_str
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
register 'nokogiri', NokogiriTemplate
|
|
650
|
+
|
|
459
651
|
# Builder template implementation. See:
|
|
460
652
|
# http://builder.rubyforge.org/
|
|
461
653
|
class BuilderTemplate < Template
|
|
462
654
|
def initialize_engine
|
|
463
|
-
|
|
655
|
+
return if defined?(::Builder)
|
|
656
|
+
require_template_library 'builder'
|
|
464
657
|
end
|
|
465
658
|
|
|
466
659
|
def prepare
|
|
@@ -477,7 +670,7 @@ module Tilt
|
|
|
477
670
|
xml.target!
|
|
478
671
|
end
|
|
479
672
|
|
|
480
|
-
def
|
|
673
|
+
def precompiled_template(locals)
|
|
481
674
|
data.to_str
|
|
482
675
|
end
|
|
483
676
|
end
|
|
@@ -499,7 +692,8 @@ module Tilt
|
|
|
499
692
|
# time when using this template engine.
|
|
500
693
|
class LiquidTemplate < Template
|
|
501
694
|
def initialize_engine
|
|
502
|
-
|
|
695
|
+
return if defined? ::Liquid::Template
|
|
696
|
+
require_template_library 'liquid'
|
|
503
697
|
end
|
|
504
698
|
|
|
505
699
|
def prepare
|
|
@@ -532,15 +726,17 @@ module Tilt
|
|
|
532
726
|
end
|
|
533
727
|
|
|
534
728
|
def initialize_engine
|
|
535
|
-
|
|
729
|
+
return if defined? ::RDiscount
|
|
730
|
+
require_template_library 'rdiscount'
|
|
536
731
|
end
|
|
537
732
|
|
|
538
733
|
def prepare
|
|
539
734
|
@engine = RDiscount.new(data, *flags)
|
|
735
|
+
@output = nil
|
|
540
736
|
end
|
|
541
737
|
|
|
542
738
|
def evaluate(scope, locals, &block)
|
|
543
|
-
@engine.to_html
|
|
739
|
+
@output ||= @engine.to_html
|
|
544
740
|
end
|
|
545
741
|
end
|
|
546
742
|
register 'markdown', RDiscountTemplate
|
|
@@ -552,108 +748,121 @@ module Tilt
|
|
|
552
748
|
# http://redcloth.org/
|
|
553
749
|
class RedClothTemplate < Template
|
|
554
750
|
def initialize_engine
|
|
555
|
-
|
|
751
|
+
return if defined? ::RedCloth
|
|
752
|
+
require_template_library 'redcloth'
|
|
556
753
|
end
|
|
557
754
|
|
|
558
755
|
def prepare
|
|
559
756
|
@engine = RedCloth.new(data)
|
|
757
|
+
@output = nil
|
|
560
758
|
end
|
|
561
759
|
|
|
562
760
|
def evaluate(scope, locals, &block)
|
|
563
|
-
@engine.to_html
|
|
761
|
+
@output ||= @engine.to_html
|
|
564
762
|
end
|
|
565
763
|
end
|
|
566
764
|
register 'textile', RedClothTemplate
|
|
567
765
|
|
|
568
766
|
|
|
569
|
-
#
|
|
570
|
-
# http://
|
|
767
|
+
# RDoc template. See:
|
|
768
|
+
# http://rdoc.rubyforge.org/
|
|
571
769
|
#
|
|
572
|
-
#
|
|
573
|
-
#
|
|
574
|
-
#
|
|
575
|
-
class
|
|
576
|
-
attr_reader :engine
|
|
577
|
-
|
|
770
|
+
# It's suggested that your program require 'rdoc/markup' and
|
|
771
|
+
# 'rdoc/markup/to_html' at load time when using this template
|
|
772
|
+
# engine.
|
|
773
|
+
class RDocTemplate < Template
|
|
578
774
|
def initialize_engine
|
|
579
|
-
|
|
775
|
+
return if defined?(::RDoc::Markup)
|
|
776
|
+
require_template_library 'rdoc/markup'
|
|
777
|
+
require_template_library 'rdoc/markup/to_html'
|
|
580
778
|
end
|
|
581
779
|
|
|
582
780
|
def prepare
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
@
|
|
586
|
-
options.each do |key, value|
|
|
587
|
-
next if %w[view view_path namespace mustaches].include?(key.to_s)
|
|
588
|
-
@engine.send("#{key}=", value) if @engine.respond_to? "#{key}="
|
|
589
|
-
end
|
|
781
|
+
markup = RDoc::Markup::ToHtml.new
|
|
782
|
+
@engine = markup.convert(data)
|
|
783
|
+
@output = nil
|
|
590
784
|
end
|
|
591
785
|
|
|
592
|
-
def evaluate(scope
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
# copy instance variables from scope to the view
|
|
596
|
-
scope.instance_variables.each do |name|
|
|
597
|
-
instance.instance_variable_set(name, scope.instance_variable_get(name))
|
|
598
|
-
end
|
|
599
|
-
|
|
600
|
-
# locals get added to the view's context
|
|
601
|
-
locals.each do |local, value|
|
|
602
|
-
instance[local] = value
|
|
603
|
-
end
|
|
604
|
-
|
|
605
|
-
# if we're passed a block it's a subview. Sticking it in yield
|
|
606
|
-
# lets us use {{yield}} in layout.html to render the actual page.
|
|
607
|
-
instance[:yield] = block.call if block
|
|
608
|
-
|
|
609
|
-
instance.template = data unless instance.compiled?
|
|
610
|
-
|
|
611
|
-
instance.to_html
|
|
786
|
+
def evaluate(scope, locals, &block)
|
|
787
|
+
@output ||= @engine.to_s
|
|
612
788
|
end
|
|
613
789
|
end
|
|
614
|
-
register '
|
|
790
|
+
register 'rdoc', RDocTemplate
|
|
615
791
|
|
|
616
792
|
|
|
617
|
-
#
|
|
618
|
-
# http://
|
|
619
|
-
|
|
620
|
-
# It's suggested that your program require 'rdoc/markup' and
|
|
621
|
-
# 'rdoc/markup/to_html' at load time when using this template
|
|
622
|
-
# engine.
|
|
623
|
-
class RDocTemplate < Template
|
|
793
|
+
# Radius Template
|
|
794
|
+
# http://github.com/jlong/radius/
|
|
795
|
+
class RadiusTemplate < Template
|
|
624
796
|
def initialize_engine
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
require_template_library 'rdoc/markup/to_html'
|
|
628
|
-
end
|
|
797
|
+
return if defined? ::Radius
|
|
798
|
+
require_template_library 'radius'
|
|
629
799
|
end
|
|
630
800
|
|
|
631
801
|
def prepare
|
|
632
|
-
markup = RDoc::Markup::ToHtml.new
|
|
633
|
-
@engine = markup.convert(data)
|
|
634
802
|
end
|
|
635
803
|
|
|
636
804
|
def evaluate(scope, locals, &block)
|
|
637
|
-
|
|
805
|
+
context = Class.new(Radius::Context).new
|
|
806
|
+
context.define_tag("yield") do
|
|
807
|
+
block.call
|
|
808
|
+
end
|
|
809
|
+
locals.each do |tag, value|
|
|
810
|
+
context.define_tag(tag) do
|
|
811
|
+
value
|
|
812
|
+
end
|
|
813
|
+
end
|
|
814
|
+
(class << context; self; end).class_eval do
|
|
815
|
+
define_method :tag_missing do |tag, attr|
|
|
816
|
+
scope.__send__(tag) # any way to support attr as args?
|
|
817
|
+
end
|
|
818
|
+
end
|
|
819
|
+
options = {:tag_prefix => 'r'}.merge(@options)
|
|
820
|
+
parser = Radius::Parser.new(context, options)
|
|
821
|
+
parser.parse(data)
|
|
638
822
|
end
|
|
639
823
|
end
|
|
640
|
-
register '
|
|
824
|
+
register 'radius', RadiusTemplate
|
|
825
|
+
|
|
641
826
|
|
|
827
|
+
# Markaby
|
|
828
|
+
# http://github.com/markaby/markaby
|
|
829
|
+
class MarkabyTemplate < Template
|
|
830
|
+
def self.builder_class
|
|
831
|
+
@builder_class ||= Class.new(Markaby::Builder) do
|
|
832
|
+
def __capture_markaby_tilt__(&block)
|
|
833
|
+
__run_markaby_tilt__ do
|
|
834
|
+
text capture(&block)
|
|
835
|
+
end
|
|
836
|
+
end
|
|
837
|
+
end
|
|
838
|
+
end
|
|
642
839
|
|
|
643
|
-
# CoffeeScript info:
|
|
644
|
-
# http://jashkenas.github.com/coffee-script/
|
|
645
|
-
class CoffeeTemplate < Template
|
|
646
840
|
def initialize_engine
|
|
647
|
-
|
|
841
|
+
return if defined? ::Markaby
|
|
842
|
+
require_template_library 'markaby'
|
|
648
843
|
end
|
|
649
844
|
|
|
650
845
|
def prepare
|
|
651
|
-
@engine = ::CoffeeScript::compile(data, options)
|
|
652
846
|
end
|
|
653
847
|
|
|
654
848
|
def evaluate(scope, locals, &block)
|
|
655
|
-
|
|
849
|
+
builder = self.class.builder_class.new({}, scope)
|
|
850
|
+
builder.locals = locals
|
|
851
|
+
|
|
852
|
+
if block
|
|
853
|
+
builder.instance_eval <<-CODE, __FILE__, __LINE__
|
|
854
|
+
def __run_markaby_tilt__
|
|
855
|
+
#{data}
|
|
856
|
+
end
|
|
857
|
+
CODE
|
|
858
|
+
|
|
859
|
+
builder.__capture_markaby_tilt__(&block)
|
|
860
|
+
else
|
|
861
|
+
builder.instance_eval(data, __FILE__, __LINE__)
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
builder.to_s
|
|
656
865
|
end
|
|
657
866
|
end
|
|
658
|
-
register '
|
|
867
|
+
register 'mab', MarkabyTemplate
|
|
659
868
|
end
|