tilt 0.7 → 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +1 -1
- data/README.md +47 -4
- data/Rakefile +7 -24
- data/TEMPLATES.md +70 -54
- data/bin/tilt +45 -16
- data/lib/tilt.rb +236 -163
- data/test/contest.rb +68 -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_radiustemplate_test.rb +66 -0
- data/test/tilt_sasstemplate_test.rb +2 -2
- data/test/tilt_stringtemplate_test.rb +1 -1
- data/test/tilt_template_test.rb +19 -1
- data/test/tilt_test.rb +9 -1
- data/tilt.gemspec +10 -7
- metadata +41 -13
- 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 = '0
|
|
4
|
+
VERSION = '1.0'
|
|
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.
|
|
@@ -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,111 @@ 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)
|
|
207
255
|
end
|
|
208
256
|
|
|
209
|
-
|
|
210
|
-
|
|
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
|
|
275
|
+
end
|
|
276
|
+
|
|
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
|
-
source = [source, template_source].join("\n")
|
|
284
|
+
source, offset = precompiled(locals)
|
|
216
285
|
offset += 1
|
|
217
|
-
|
|
218
|
-
# add the new method
|
|
219
286
|
CompileSite.module_eval <<-RUBY, eval_file, line - offset
|
|
220
287
|
def #{method_name}(locals)
|
|
221
288
|
#{source}
|
|
222
289
|
end
|
|
223
290
|
RUBY
|
|
224
291
|
|
|
225
|
-
# setup a finalizer to remove the newly added method
|
|
226
292
|
ObjectSpace.define_finalizer self,
|
|
227
293
|
Template.compiled_template_method_remover(CompileSite, method_name)
|
|
228
294
|
end
|
|
@@ -240,14 +306,6 @@ module Tilt
|
|
|
240
306
|
end
|
|
241
307
|
end
|
|
242
308
|
end
|
|
243
|
-
|
|
244
|
-
def require_template_library(name)
|
|
245
|
-
if Thread.list.size > 1
|
|
246
|
-
warn "WARN: tilt autoloading '#{name}' in a non thread-safe way; " +
|
|
247
|
-
"explicit require '#{name}' suggested."
|
|
248
|
-
end
|
|
249
|
-
require name
|
|
250
|
-
end
|
|
251
309
|
end
|
|
252
310
|
|
|
253
311
|
# Extremely simple template cache implementation. Calling applications
|
|
@@ -282,7 +340,7 @@ module Tilt
|
|
|
282
340
|
@code = "%Q{#{data}}"
|
|
283
341
|
end
|
|
284
342
|
|
|
285
|
-
def
|
|
343
|
+
def precompiled_template(locals)
|
|
286
344
|
@code
|
|
287
345
|
end
|
|
288
346
|
end
|
|
@@ -292,72 +350,99 @@ module Tilt
|
|
|
292
350
|
# ERB template implementation. See:
|
|
293
351
|
# http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html
|
|
294
352
|
class ERBTemplate < Template
|
|
353
|
+
@@default_output_variable = '_erbout'
|
|
354
|
+
|
|
355
|
+
def self.default_output_variable
|
|
356
|
+
@@default_output_variable
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
def self.default_output_variable=(name)
|
|
360
|
+
@@default_output_variable = name
|
|
361
|
+
end
|
|
362
|
+
|
|
295
363
|
def initialize_engine
|
|
296
|
-
|
|
364
|
+
return if defined? ::ERB
|
|
365
|
+
require_template_library 'erb'
|
|
297
366
|
end
|
|
298
367
|
|
|
299
368
|
def prepare
|
|
300
|
-
@outvar =
|
|
369
|
+
@outvar = options[:outvar] || self.class.default_output_variable
|
|
301
370
|
@engine = ::ERB.new(data, options[:safe], options[:trim], @outvar)
|
|
302
371
|
end
|
|
303
372
|
|
|
304
|
-
def
|
|
305
|
-
@engine.src
|
|
373
|
+
def precompiled_template(locals)
|
|
374
|
+
source = @engine.src
|
|
375
|
+
source
|
|
306
376
|
end
|
|
307
377
|
|
|
308
|
-
def
|
|
309
|
-
|
|
378
|
+
def precompiled_preamble(locals)
|
|
379
|
+
<<-RUBY
|
|
380
|
+
begin
|
|
381
|
+
__original_outvar = #{@outvar} if defined?(#{@outvar})
|
|
382
|
+
#{super}
|
|
383
|
+
RUBY
|
|
310
384
|
end
|
|
311
385
|
|
|
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
|
|
386
|
+
def precompiled_postamble(locals)
|
|
387
|
+
<<-RUBY
|
|
388
|
+
#{super}
|
|
389
|
+
ensure
|
|
390
|
+
#{@outvar} = __original_outvar
|
|
391
|
+
end
|
|
392
|
+
RUBY
|
|
325
393
|
end
|
|
326
394
|
|
|
327
395
|
# ERB generates a line to specify the character coding of the generated
|
|
328
396
|
# source in 1.9. Account for this in the line offset.
|
|
329
397
|
if RUBY_VERSION >= '1.9.0'
|
|
330
|
-
def
|
|
398
|
+
def precompiled(locals)
|
|
331
399
|
source, offset = super
|
|
332
400
|
[source, offset + 1]
|
|
333
401
|
end
|
|
334
402
|
end
|
|
335
403
|
end
|
|
404
|
+
|
|
336
405
|
%w[erb rhtml].each { |ext| register ext, ERBTemplate }
|
|
337
406
|
|
|
338
407
|
|
|
339
408
|
# Erubis template implementation. See:
|
|
340
409
|
# http://www.kuwata-lab.com/erubis/
|
|
410
|
+
#
|
|
411
|
+
# ErubisTemplate supports the following additional options, which are not
|
|
412
|
+
# passed down to the Erubis engine:
|
|
413
|
+
#
|
|
414
|
+
# :engine_class allows you to specify a custom engine class to use
|
|
415
|
+
# instead of the default (which is ::Erubis::Eruby).
|
|
416
|
+
#
|
|
417
|
+
# :escape_html when true, ::Erubis::EscapedEruby will be used as
|
|
418
|
+
# the engine class instead of the default. All content
|
|
419
|
+
# within <%= %> blocks will be automatically html escaped.
|
|
341
420
|
class ErubisTemplate < ERBTemplate
|
|
342
421
|
def initialize_engine
|
|
343
|
-
|
|
422
|
+
return if defined? ::Erubis
|
|
423
|
+
require_template_library 'erubis'
|
|
344
424
|
end
|
|
345
425
|
|
|
346
426
|
def prepare
|
|
347
427
|
@options.merge!(:preamble => false, :postamble => false)
|
|
348
|
-
@outvar =
|
|
349
|
-
|
|
428
|
+
@outvar = options.delete(:outvar) || self.class.default_output_variable
|
|
429
|
+
engine_class = options.delete(:engine_class)
|
|
430
|
+
engine_class = ::Erubis::EscapedEruby if options.delete(:escape_html)
|
|
431
|
+
@engine = (engine_class || ::Erubis::Eruby).new(data, options)
|
|
350
432
|
end
|
|
351
433
|
|
|
352
|
-
def
|
|
353
|
-
["#{@outvar} = _buf = ''"
|
|
434
|
+
def precompiled_preamble(locals)
|
|
435
|
+
[super, "#{@outvar} = _buf = ''"].join("\n")
|
|
354
436
|
end
|
|
355
437
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
438
|
+
def precompiled_postamble(locals)
|
|
439
|
+
["_buf", super].join("\n")
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# Erubis doesn't have ERB's line-off-by-one under 1.9 problem.
|
|
443
|
+
# Override and adjust back.
|
|
359
444
|
if RUBY_VERSION >= '1.9.0'
|
|
360
|
-
def
|
|
445
|
+
def precompiled(locals)
|
|
361
446
|
source, offset = super
|
|
362
447
|
[source, offset - 1]
|
|
363
448
|
end
|
|
@@ -370,26 +455,48 @@ module Tilt
|
|
|
370
455
|
# http://haml.hamptoncatlin.com/
|
|
371
456
|
class HamlTemplate < Template
|
|
372
457
|
def initialize_engine
|
|
373
|
-
|
|
458
|
+
return if defined? ::Haml::Engine
|
|
459
|
+
require_template_library 'haml'
|
|
374
460
|
end
|
|
375
461
|
|
|
376
462
|
def prepare
|
|
377
|
-
|
|
463
|
+
options = @options.merge(:filename => eval_file, :line => line)
|
|
464
|
+
@engine = ::Haml::Engine.new(data, options)
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
def evaluate(scope, locals, &block)
|
|
468
|
+
if @engine.respond_to?(:precompiled_method_return_value, true)
|
|
469
|
+
super
|
|
470
|
+
else
|
|
471
|
+
@engine.render(scope, locals, &block)
|
|
472
|
+
end
|
|
378
473
|
end
|
|
379
474
|
|
|
380
475
|
# Precompiled Haml source. Taken from the precompiled_with_ambles
|
|
381
476
|
# method in Haml::Precompiler:
|
|
382
477
|
# http://github.com/nex3/haml/blob/master/lib/haml/precompiler.rb#L111-126
|
|
383
|
-
def
|
|
478
|
+
def precompiled_template(locals)
|
|
479
|
+
@engine.precompiled
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
def precompiled_preamble(locals)
|
|
483
|
+
local_assigns = super
|
|
384
484
|
@engine.instance_eval do
|
|
385
485
|
<<-RUBY
|
|
386
|
-
_haml_locals = locals
|
|
387
486
|
begin
|
|
388
487
|
extend Haml::Helpers
|
|
389
488
|
_hamlout = @haml_buffer = Haml::Buffer.new(@haml_buffer, #{options_for_buffer.inspect})
|
|
390
489
|
_erbout = _hamlout.buffer
|
|
391
490
|
__in_erb_template = true
|
|
392
|
-
|
|
491
|
+
_haml_locals = locals
|
|
492
|
+
#{local_assigns}
|
|
493
|
+
RUBY
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def precompiled_postamble(locals)
|
|
498
|
+
@engine.instance_eval do
|
|
499
|
+
<<-RUBY
|
|
393
500
|
#{precompiled_method_return_value}
|
|
394
501
|
ensure
|
|
395
502
|
@haml_buffer = @haml_buffer.upper
|
|
@@ -397,16 +504,6 @@ module Tilt
|
|
|
397
504
|
RUBY
|
|
398
505
|
end
|
|
399
506
|
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
507
|
end
|
|
411
508
|
register 'haml', HamlTemplate
|
|
412
509
|
|
|
@@ -417,7 +514,8 @@ module Tilt
|
|
|
417
514
|
# Sass templates do not support object scopes, locals, or yield.
|
|
418
515
|
class SassTemplate < Template
|
|
419
516
|
def initialize_engine
|
|
420
|
-
|
|
517
|
+
return if defined? ::Sass::Engine
|
|
518
|
+
require_template_library 'sass'
|
|
421
519
|
end
|
|
422
520
|
|
|
423
521
|
def prepare
|
|
@@ -442,7 +540,8 @@ module Tilt
|
|
|
442
540
|
# Less templates do not support object scopes, locals, or yield.
|
|
443
541
|
class LessTemplate < Template
|
|
444
542
|
def initialize_engine
|
|
445
|
-
|
|
543
|
+
return if defined? ::Less::Engine
|
|
544
|
+
require_template_library 'less'
|
|
446
545
|
end
|
|
447
546
|
|
|
448
547
|
def prepare
|
|
@@ -460,7 +559,8 @@ module Tilt
|
|
|
460
559
|
# http://builder.rubyforge.org/
|
|
461
560
|
class BuilderTemplate < Template
|
|
462
561
|
def initialize_engine
|
|
463
|
-
|
|
562
|
+
return if defined?(::Builder)
|
|
563
|
+
require_template_library 'builder'
|
|
464
564
|
end
|
|
465
565
|
|
|
466
566
|
def prepare
|
|
@@ -477,7 +577,7 @@ module Tilt
|
|
|
477
577
|
xml.target!
|
|
478
578
|
end
|
|
479
579
|
|
|
480
|
-
def
|
|
580
|
+
def precompiled_template(locals)
|
|
481
581
|
data.to_str
|
|
482
582
|
end
|
|
483
583
|
end
|
|
@@ -499,7 +599,8 @@ module Tilt
|
|
|
499
599
|
# time when using this template engine.
|
|
500
600
|
class LiquidTemplate < Template
|
|
501
601
|
def initialize_engine
|
|
502
|
-
|
|
602
|
+
return if defined? ::Liquid::Template
|
|
603
|
+
require_template_library 'liquid'
|
|
503
604
|
end
|
|
504
605
|
|
|
505
606
|
def prepare
|
|
@@ -532,15 +633,17 @@ module Tilt
|
|
|
532
633
|
end
|
|
533
634
|
|
|
534
635
|
def initialize_engine
|
|
535
|
-
|
|
636
|
+
return if defined? ::RDiscount
|
|
637
|
+
require_template_library 'rdiscount'
|
|
536
638
|
end
|
|
537
639
|
|
|
538
640
|
def prepare
|
|
539
641
|
@engine = RDiscount.new(data, *flags)
|
|
642
|
+
@output = nil
|
|
540
643
|
end
|
|
541
644
|
|
|
542
645
|
def evaluate(scope, locals, &block)
|
|
543
|
-
@engine.to_html
|
|
646
|
+
@output ||= @engine.to_html
|
|
544
647
|
end
|
|
545
648
|
end
|
|
546
649
|
register 'markdown', RDiscountTemplate
|
|
@@ -552,68 +655,22 @@ module Tilt
|
|
|
552
655
|
# http://redcloth.org/
|
|
553
656
|
class RedClothTemplate < Template
|
|
554
657
|
def initialize_engine
|
|
555
|
-
|
|
658
|
+
return if defined? ::RedCloth
|
|
659
|
+
require_template_library 'redcloth'
|
|
556
660
|
end
|
|
557
661
|
|
|
558
662
|
def prepare
|
|
559
663
|
@engine = RedCloth.new(data)
|
|
664
|
+
@output = nil
|
|
560
665
|
end
|
|
561
666
|
|
|
562
667
|
def evaluate(scope, locals, &block)
|
|
563
|
-
@engine.to_html
|
|
668
|
+
@output ||= @engine.to_html
|
|
564
669
|
end
|
|
565
670
|
end
|
|
566
671
|
register 'textile', RedClothTemplate
|
|
567
672
|
|
|
568
673
|
|
|
569
|
-
# Mustache is written and maintained by Chris Wanstrath. See:
|
|
570
|
-
# http://github.com/defunkt/mustache
|
|
571
|
-
#
|
|
572
|
-
# When a scope argument is provided to MustacheTemplate#render, the
|
|
573
|
-
# instance variables are copied from the scope object to the Mustache
|
|
574
|
-
# view.
|
|
575
|
-
class MustacheTemplate < Template
|
|
576
|
-
attr_reader :engine
|
|
577
|
-
|
|
578
|
-
def initialize_engine
|
|
579
|
-
require_template_library 'mustache' unless defined? ::Mustache
|
|
580
|
-
end
|
|
581
|
-
|
|
582
|
-
def prepare
|
|
583
|
-
Mustache.view_namespace = options[:namespace]
|
|
584
|
-
Mustache.view_path = options[:view_path] || options[:mustaches]
|
|
585
|
-
@engine = options[:view] || Mustache.view_class(name)
|
|
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
|
|
590
|
-
end
|
|
591
|
-
|
|
592
|
-
def evaluate(scope=nil, locals={}, &block)
|
|
593
|
-
instance = @engine.new
|
|
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
|
|
612
|
-
end
|
|
613
|
-
end
|
|
614
|
-
register 'mustache', MustacheTemplate
|
|
615
|
-
|
|
616
|
-
|
|
617
674
|
# RDoc template. See:
|
|
618
675
|
# http://rdoc.rubyforge.org/
|
|
619
676
|
#
|
|
@@ -622,38 +679,54 @@ module Tilt
|
|
|
622
679
|
# engine.
|
|
623
680
|
class RDocTemplate < Template
|
|
624
681
|
def initialize_engine
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
end
|
|
682
|
+
return if defined?(::RDoc::Markup)
|
|
683
|
+
require_template_library 'rdoc/markup'
|
|
684
|
+
require_template_library 'rdoc/markup/to_html'
|
|
629
685
|
end
|
|
630
686
|
|
|
631
687
|
def prepare
|
|
632
688
|
markup = RDoc::Markup::ToHtml.new
|
|
633
689
|
@engine = markup.convert(data)
|
|
690
|
+
@output = nil
|
|
634
691
|
end
|
|
635
692
|
|
|
636
693
|
def evaluate(scope, locals, &block)
|
|
637
|
-
@engine.to_s
|
|
694
|
+
@output ||= @engine.to_s
|
|
638
695
|
end
|
|
639
696
|
end
|
|
640
697
|
register 'rdoc', RDocTemplate
|
|
641
698
|
|
|
642
699
|
|
|
643
|
-
#
|
|
644
|
-
# http://
|
|
645
|
-
class
|
|
700
|
+
# Radius Template
|
|
701
|
+
# http://github.com/jlong/radius/
|
|
702
|
+
class RadiusTemplate < Template
|
|
646
703
|
def initialize_engine
|
|
647
|
-
|
|
704
|
+
return if defined? ::Radius
|
|
705
|
+
require_template_library 'radius'
|
|
648
706
|
end
|
|
649
707
|
|
|
650
708
|
def prepare
|
|
651
|
-
@engine = ::CoffeeScript::compile(data, options)
|
|
652
709
|
end
|
|
653
710
|
|
|
654
711
|
def evaluate(scope, locals, &block)
|
|
655
|
-
|
|
712
|
+
context = Class.new(Radius::Context).new
|
|
713
|
+
context.define_tag("yield") do
|
|
714
|
+
block.call
|
|
715
|
+
end
|
|
716
|
+
locals.each do |tag, value|
|
|
717
|
+
context.define_tag(tag) do
|
|
718
|
+
value
|
|
719
|
+
end
|
|
720
|
+
end
|
|
721
|
+
(class << context; self; end).class_eval do
|
|
722
|
+
define_method :tag_missing do |tag, attr, &block|
|
|
723
|
+
scope.__send__(tag) # any way to support attr as args?
|
|
724
|
+
end
|
|
725
|
+
end
|
|
726
|
+
options = {:tag_prefix => 'r'}.merge(@options)
|
|
727
|
+
parser = Radius::Parser.new(context, options)
|
|
728
|
+
parser.parse(data)
|
|
656
729
|
end
|
|
657
730
|
end
|
|
658
|
-
register '
|
|
731
|
+
register 'radius', RadiusTemplate
|
|
659
732
|
end
|