tilt 1.2 → 1.3.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.
Files changed (43) hide show
  1. data/README.md +54 -24
  2. data/TEMPLATES.md +250 -175
  3. data/lib/tilt/builder.rb +40 -0
  4. data/lib/tilt/coffee.rb +50 -0
  5. data/lib/tilt/creole.rb +28 -0
  6. data/lib/tilt/css.rb +68 -0
  7. data/lib/tilt/erb.rb +110 -0
  8. data/lib/tilt/haml.rb +64 -0
  9. data/lib/tilt/liquid.rb +41 -0
  10. data/lib/tilt/markaby.rb +52 -0
  11. data/lib/tilt/markdown.rb +131 -0
  12. data/lib/tilt/nokogiri.rb +43 -0
  13. data/lib/tilt/radius.rb +51 -0
  14. data/lib/tilt/rdoc.rb +32 -0
  15. data/lib/tilt/string.rb +21 -0
  16. data/lib/tilt/template.rb +285 -0
  17. data/lib/tilt/textile.rb +25 -0
  18. data/lib/tilt.rb +102 -805
  19. data/test/tilt_blueclothtemplate_test.rb +11 -25
  20. data/test/tilt_buildertemplate_test.rb +16 -1
  21. data/test/tilt_coffeescripttemplate_test.rb +37 -1
  22. data/test/tilt_creoletemplate_test.rb +24 -0
  23. data/test/tilt_erbtemplate_test.rb +23 -19
  24. data/test/tilt_erubistemplate_test.rb +17 -2
  25. data/test/tilt_fallback_test.rb +122 -0
  26. data/test/tilt_hamltemplate_test.rb +9 -4
  27. data/test/tilt_kramdown_test.rb +42 -0
  28. data/test/tilt_lesstemplate_test.rb +5 -0
  29. data/test/tilt_liquidtemplate_test.rb +5 -0
  30. data/test/tilt_markaby_test.rb +5 -0
  31. data/test/tilt_markdown_test.rb +149 -0
  32. data/test/tilt_marukutemplate_test.rb +48 -0
  33. data/test/tilt_nokogiritemplate_test.rb +20 -7
  34. data/test/tilt_radiustemplate_test.rb +5 -0
  35. data/test/tilt_rdiscounttemplate_test.rb +21 -6
  36. data/test/tilt_rdoctemplate_test.rb +6 -1
  37. data/test/tilt_redcarpettemplate_test.rb +55 -0
  38. data/test/tilt_redclothtemplate_test.rb +4 -0
  39. data/test/tilt_sasstemplate_test.rb +21 -0
  40. data/test/tilt_stringtemplate_test.rb +15 -3
  41. data/test/tilt_template_test.rb +6 -0
  42. data/tilt.gemspec +28 -7
  43. metadata +105 -7
data/lib/tilt.rb CHANGED
@@ -1,23 +1,57 @@
1
1
  module Tilt
2
- TOPOBJECT = defined?(BasicObject) ? BasicObject : Object
3
- VERSION = '1.2'
2
+ VERSION = '1.3.1'
4
3
 
5
- @template_mappings = {}
4
+ @preferred_mappings = Hash.new
5
+ @template_mappings = Hash.new { |h, k| h[k] = [] }
6
6
 
7
7
  # Hash of template path pattern => template implementation class mappings.
8
8
  def self.mappings
9
9
  @template_mappings
10
10
  end
11
11
 
12
+ def self.normalize(ext)
13
+ ext.to_s.downcase.sub(/^\./, '')
14
+ end
15
+
12
16
  # Register a template implementation by file extension.
13
- def self.register(ext, template_class)
14
- ext = ext.to_s.sub(/^\./, '')
15
- mappings[ext.downcase] = template_class
17
+ def self.register(template_class, *extensions)
18
+ if template_class.respond_to?(:to_str)
19
+ # Support register(ext, template_class) too
20
+ extensions, template_class = [template_class], extensions[0]
21
+ end
22
+
23
+ extensions.each do |ext|
24
+ ext = normalize(ext)
25
+ mappings[ext].unshift(template_class).uniq!
26
+ end
27
+ end
28
+
29
+ # Makes a template class preferred for the given file extensions. If you
30
+ # don't provide any extensions, it will be preferred for all its already
31
+ # registered extensions:
32
+ #
33
+ # # Prefer RDiscount for its registered file extensions:
34
+ # Tilt.prefer(Tilt::RDiscountTemplate)
35
+ #
36
+ # # Prefer RDiscount only for the .md extensions:
37
+ # Tilt.prefer(Tilt::RDiscountTemplate, '.md')
38
+ def self.prefer(template_class, *extensions)
39
+ if extensions.empty?
40
+ mappings.each do |ext, klasses|
41
+ @preferred_mappings[ext] = template_class if klasses.include? template_class
42
+ end
43
+ else
44
+ extensions.each do |ext|
45
+ ext = normalize(ext)
46
+ register(template_class, ext)
47
+ @preferred_mappings[ext] = template_class
48
+ end
49
+ end
16
50
  end
17
51
 
18
52
  # Returns true when a template exists on an exact match of the provided file extension
19
53
  def self.registered?(ext)
20
- mappings.key?(ext.downcase)
54
+ mappings.key?(ext.downcase) && !mappings[ext.downcase].empty?
21
55
  end
22
56
 
23
57
  # Create a new template for the given file using the file's extension
@@ -34,297 +68,47 @@ module Tilt
34
68
  # extension. Return nil when no implementation is found.
35
69
  def self.[](file)
36
70
  pattern = file.to_s.downcase
37
- unless registered?(pattern)
71
+ until pattern.empty? || registered?(pattern)
38
72
  pattern = File.basename(pattern)
39
- pattern.sub!(/^[^.]*\.?/, '') until (pattern.empty? || registered?(pattern))
73
+ pattern.sub!(/^[^.]*\.?/, '')
40
74
  end
41
- @template_mappings[pattern]
42
- end
43
75
 
44
- # Deprecated module.
45
- module CompileSite
46
- def self.append_features(*)
47
- warn "WARNING: Tilt::CompileSite is deprecated and will be removed in Tilt 2.0 (#{caller.first})."
48
- end
49
- end
50
-
51
- # Base class for template implementations. Subclasses must implement
52
- # the #prepare method and one of the #evaluate or #precompiled_template
53
- # methods.
54
- class Template
55
- # Template source; loaded from a file or given directly.
56
- attr_reader :data
57
-
58
- # The name of the file where the template data was loaded from.
59
- attr_reader :file
60
-
61
- # The line number in #file where template data was loaded from.
62
- attr_reader :line
63
-
64
- # A Hash of template engine specific options. This is passed directly
65
- # to the underlying engine and is not used by the generic template
66
- # interface.
67
- attr_reader :options
68
-
69
- # Used to determine if this class's initialize_engine method has
70
- # been called yet.
71
- @engine_initialized = false
72
- class << self
73
- attr_accessor :engine_initialized
74
- alias engine_initialized? engine_initialized
75
- end
76
+ # Try to find a preferred engine.
77
+ preferred_klass = @preferred_mappings[pattern]
78
+ return preferred_klass if preferred_klass
76
79
 
77
- # Create a new template with the file, line, and options specified. By
78
- # default, template data is read from the file. When a block is given,
79
- # it should read template data and return as a String. When file is nil,
80
- # a block is required.
81
- #
82
- # All arguments are optional.
83
- def initialize(file=nil, line=1, options={}, &block)
84
- @file, @line, @options = nil, 1, {}
85
-
86
- [options, line, file].compact.each do |arg|
87
- case
88
- when arg.respond_to?(:to_str) ; @file = arg.to_str
89
- when arg.respond_to?(:to_int) ; @line = arg.to_int
90
- when arg.respond_to?(:to_hash) ; @options = arg.to_hash.dup
91
- else raise TypeError
92
- end
93
- end
94
-
95
- raise ArgumentError, "file or block required" if (@file || block).nil?
80
+ # Fall back to the general list of mappings.
81
+ klasses = @template_mappings[pattern]
96
82
 
97
- # call the initialize_engine method if this is the very first time
98
- # an instance of this class has been created.
99
- if !self.class.engine_initialized?
100
- initialize_engine
101
- self.class.engine_initialized = true
83
+ # Try to find an engine which is already loaded.
84
+ template = klasses.detect do |klass|
85
+ if klass.respond_to?(:engine_initialized?)
86
+ klass.engine_initialized?
102
87
  end
103
-
104
- # used to hold compiled template methods
105
- @compiled_method = {}
106
-
107
- # used on 1.9 to set the encoding if it is not set elsewhere (like a magic comment)
108
- # currently only used if template compiles to ruby
109
- @default_encoding = @options.delete :default_encoding
110
-
111
- # load template data and prepare (uses binread to avoid encoding issues)
112
- @reader = block || lambda { |t| File.respond_to?(:binread) ? File.binread(@file) : File.read(@file) }
113
- @data = @reader.call(self)
114
- prepare
115
- end
116
-
117
- # Render the template in the given scope with the locals specified. If a
118
- # block is given, it is typically available within the template via
119
- # +yield+.
120
- def render(scope=Object.new, locals={}, &block)
121
- evaluate scope, locals || {}, &block
122
88
  end
123
89
 
124
- # The basename of the template file.
125
- def basename(suffix='')
126
- File.basename(file, suffix) if file
127
- end
90
+ return template if template
128
91
 
129
- # The template file's basename with all extensions chomped off.
130
- def name
131
- basename.split('.', 2).first if basename
132
- end
133
-
134
- # The filename used in backtraces to describe the template.
135
- def eval_file
136
- file || '(__TEMPLATE__)'
137
- end
92
+ # Try each of the classes until one succeeds. If all of them fails,
93
+ # we'll raise the error of the first class.
94
+ first_failure = nil
138
95
 
139
- protected
140
- # Called once and only once for each template subclass the first time
141
- # the template class is initialized. This should be used to require the
142
- # underlying template library and perform any initial setup.
143
- def initialize_engine
144
- end
145
-
146
- # Like Kernel::require but issues a warning urging a manual require when
147
- # running under a threaded environment.
148
- def require_template_library(name)
149
- if Thread.list.size > 1
150
- warn "WARN: tilt autoloading '#{name}' in a non thread-safe way; " +
151
- "explicit require '#{name}' suggested."
152
- end
153
- require name
154
- end
155
-
156
- # Do whatever preparation is necessary to setup the underlying template
157
- # engine. Called immediately after template data is loaded. Instance
158
- # variables set in this method are available when #evaluate is called.
159
- #
160
- # Subclasses must provide an implementation of this method.
161
- def prepare
162
- if respond_to?(:compile!)
163
- # backward compat with tilt < 0.6; just in case
164
- warn 'Tilt::Template#compile! is deprecated; implement #prepare instead.'
165
- compile!
96
+ klasses.each do |klass|
97
+ begin
98
+ klass.new { '' }
99
+ rescue Exception => ex
100
+ first_failure ||= ex
101
+ next
166
102
  else
167
- raise NotImplementedError
168
- end
169
- end
170
-
171
- # Process the template and return the result. The first time this
172
- # method is called, the template source is evaluated with instance_eval.
173
- # On the sequential method calls it will compile the template to an
174
- # unbound method which will lead to better performance. In any case,
175
- # template executation is guaranteed to be performed in the scope object
176
- # with the locals specified and with support for yielding to the block.
177
- def evaluate(scope, locals, &block)
178
- # Redefine itself to use method compilation the next time:
179
- def self.evaluate(scope, locals, &block)
180
- method = compiled_method(locals.keys)
181
- method.bind(scope).call(locals, &block)
182
- end
183
-
184
- # Use instance_eval the first time:
185
- evaluate_source(scope, locals, &block)
186
- end
187
-
188
- # Generates all template source by combining the preamble, template, and
189
- # postamble and returns a two-tuple of the form: [source, offset], where
190
- # source is the string containing (Ruby) source code for the template and
191
- # offset is the integer line offset where line reporting should begin.
192
- #
193
- # Template subclasses may override this method when they need complete
194
- # control over source generation or want to adjust the default line
195
- # offset. In most cases, overriding the #precompiled_template method is
196
- # easier and more appropriate.
197
- def precompiled(locals)
198
- preamble = precompiled_preamble(locals)
199
- template = precompiled_template(locals)
200
- magic_comment = extract_magic_comment(template)
201
- if magic_comment
202
- # Magic comment e.g. "# coding: utf-8" has to be in the first line.
203
- # So we copy the magic comment to the first line.
204
- preamble = magic_comment + "\n" + preamble
205
- end
206
- parts = [
207
- preamble,
208
- template,
209
- precompiled_postamble(locals)
210
- ]
211
- [parts.join("\n"), preamble.count("\n") + 1]
212
- end
213
-
214
- # A string containing the (Ruby) source code for the template. The
215
- # default Template#evaluate implementation requires either this method
216
- # or the #precompiled method be overridden. When defined, the base
217
- # Template guarantees correct file/line handling, locals support, custom
218
- # scopes, and support for template compilation when the scope object
219
- # allows it.
220
- def precompiled_template(locals)
221
- raise NotImplementedError
222
- end
223
-
224
- # Generates preamble code for initializing template state, and performing
225
- # locals assignment. The default implementation performs locals
226
- # assignment only. Lines included in the preamble are subtracted from the
227
- # source line offset, so adding code to the preamble does not effect line
228
- # reporting in Kernel::caller and backtraces.
229
- def precompiled_preamble(locals)
230
- locals.map { |k,v| "#{k} = locals[:#{k}]" }.join("\n")
231
- end
232
-
233
- # Generates postamble code for the precompiled template source. The
234
- # string returned from this method is appended to the precompiled
235
- # template source.
236
- def precompiled_postamble(locals)
237
- ''
238
- end
239
-
240
- # The compiled method for the locals keys provided.
241
- def compiled_method(locals_keys)
242
- @compiled_method[locals_keys] ||=
243
- compile_template_method(locals_keys)
244
- end
245
-
246
- private
247
- # Evaluate the template source in the context of the scope object.
248
- def evaluate_source(scope, locals, &block)
249
- source, offset = precompiled(locals)
250
- scope.instance_eval(source, eval_file, line - offset)
251
- end
252
-
253
- # JRuby doesn't allow Object#instance_eval to yield to the block it's
254
- # closed over. This is by design and (ostensibly) something that will
255
- # change in MRI, though no current MRI version tested (1.8.6 - 1.9.2)
256
- # exhibits the behavior. More info here:
257
- #
258
- # http://jira.codehaus.org/browse/JRUBY-2599
259
- #
260
- # Additionally, JRuby's eval line reporting is off by one compared to
261
- # all MRI versions tested.
262
- #
263
- # We redefine evaluate_source to work around both issues.
264
- if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
265
- undef evaluate_source
266
- def evaluate_source(scope, locals, &block)
267
- source, offset = precompiled(locals)
268
- file, lineno = eval_file, (line - offset) - 1
269
- scope.instance_eval { Kernel::eval(source, binding, file, lineno) }
103
+ return klass
270
104
  end
271
105
  end
272
106
 
273
- def compile_template_method(locals)
274
- source, offset = precompiled(locals)
275
- offset += 5
276
- method_name = "__tilt_#{Thread.current.object_id.abs}"
277
- Object.class_eval <<-RUBY, eval_file, line - offset
278
- #{extract_magic_comment source}
279
- TOPOBJECT.class_eval do
280
- def #{method_name}(locals)
281
- Thread.current[:tilt_vars] = [self, locals]
282
- class << self
283
- this, locals = Thread.current[:tilt_vars]
284
- this.instance_eval do
285
- #{source}
286
- end
287
- end
288
- end
289
- end
290
- RUBY
291
- unbind_compiled_method(method_name)
292
- end
293
-
294
- def unbind_compiled_method(method_name)
295
- method = TOPOBJECT.instance_method(method_name)
296
- TOPOBJECT.class_eval { remove_method(method_name) }
297
- method
298
- end
299
-
300
- def extract_magic_comment(script)
301
- comment = script.slice(/\A[ \t]*\#.*coding\s*[=:]\s*([[:alnum:]\-_]+).*$/)
302
- return comment if comment and not %w[ascii-8bit binary].include?($1.downcase)
303
- "# coding: #{@default_encoding}" if @default_encoding
304
- end
107
+ raise first_failure if first_failure
108
+ end
305
109
 
306
- # Special case Ruby 1.9.1's broken yield.
307
- #
308
- # http://github.com/rtomayko/tilt/commit/20c01a5
309
- # http://redmine.ruby-lang.org/issues/show/3601
310
- #
311
- # Remove when 1.9.2 dominates 1.9.1 installs in the wild.
312
- if RUBY_VERSION =~ /^1.9.1/
313
- undef compile_template_method
314
- def compile_template_method(locals)
315
- source, offset = precompiled(locals)
316
- offset += 1
317
- method_name = "__tilt_#{Thread.current.object_id}"
318
- Object.class_eval <<-RUBY, eval_file, line - offset
319
- TOPOBJECT.class_eval do
320
- def #{method_name}(locals)
321
- #{source}
322
- end
323
- end
324
- RUBY
325
- unbind_compiled_method(method_name)
326
- end
327
- end
110
+ # Deprecated module.
111
+ module CompileSite
328
112
  end
329
113
 
330
114
  # Extremely simple template cache implementation. Calling applications
@@ -351,539 +135,52 @@ module Tilt
351
135
 
352
136
  # Template Implementations ================================================
353
137
 
138
+ require 'tilt/string'
139
+ register StringTemplate, 'str'
354
140
 
355
- # The template source is evaluated as a Ruby string. The #{} interpolation
356
- # syntax can be used to generated dynamic output.
357
- class StringTemplate < Template
358
- def prepare
359
- @code = "%Q{#{data}}"
360
- end
361
-
362
- def precompiled_template(locals)
363
- @code
364
- end
365
- end
366
- register 'str', StringTemplate
367
-
368
-
369
- # ERB template implementation. See:
370
- # http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html
371
- class ERBTemplate < Template
372
- @@default_output_variable = '_erbout'
373
-
374
- def self.default_output_variable
375
- @@default_output_variable
376
- end
377
-
378
- def self.default_output_variable=(name)
379
- @@default_output_variable = name
380
- end
381
-
382
- def initialize_engine
383
- return if defined? ::ERB
384
- require_template_library 'erb'
385
- end
386
-
387
- def prepare
388
- @outvar = options[:outvar] || self.class.default_output_variable
389
- @engine = ::ERB.new(data, options[:safe], options[:trim], @outvar)
390
- end
391
-
392
- def precompiled_template(locals)
393
- source = @engine.src
394
- source
395
- end
396
-
397
- def precompiled_preamble(locals)
398
- <<-RUBY
399
- begin
400
- __original_outvar = #{@outvar} if defined?(#{@outvar})
401
- #{super}
402
- RUBY
403
- end
404
-
405
- def precompiled_postamble(locals)
406
- <<-RUBY
407
- #{super}
408
- ensure
409
- #{@outvar} = __original_outvar
410
- end
411
- RUBY
412
- end
413
-
414
- # ERB generates a line to specify the character coding of the generated
415
- # source in 1.9. Account for this in the line offset.
416
- if RUBY_VERSION >= '1.9.0'
417
- def precompiled(locals)
418
- source, offset = super
419
- [source, offset + 1]
420
- end
421
- end
422
- end
423
-
424
- %w[erb rhtml].each { |ext| register ext, ERBTemplate }
425
-
426
-
427
- # Erubis template implementation. See:
428
- # http://www.kuwata-lab.com/erubis/
429
- #
430
- # ErubisTemplate supports the following additional options, which are not
431
- # passed down to the Erubis engine:
432
- #
433
- # :engine_class allows you to specify a custom engine class to use
434
- # instead of the default (which is ::Erubis::Eruby).
435
- #
436
- # :escape_html when true, ::Erubis::EscapedEruby will be used as
437
- # the engine class instead of the default. All content
438
- # within <%= %> blocks will be automatically html escaped.
439
- class ErubisTemplate < ERBTemplate
440
- def initialize_engine
441
- return if defined? ::Erubis
442
- require_template_library 'erubis'
443
- end
444
-
445
- def prepare
446
- @options.merge!(:preamble => false, :postamble => false)
447
- @outvar = options.delete(:outvar) || self.class.default_output_variable
448
- engine_class = options.delete(:engine_class)
449
- engine_class = ::Erubis::EscapedEruby if options.delete(:escape_html)
450
- @engine = (engine_class || ::Erubis::Eruby).new(data, options)
451
- end
452
-
453
- def precompiled_preamble(locals)
454
- [super, "#{@outvar} = _buf = ''"].join("\n")
455
- end
456
-
457
- def precompiled_postamble(locals)
458
- ["_buf", super].join("\n")
459
- end
460
-
461
- # Erubis doesn't have ERB's line-off-by-one under 1.9 problem.
462
- # Override and adjust back.
463
- if RUBY_VERSION >= '1.9.0'
464
- def precompiled(locals)
465
- source, offset = super
466
- [source, offset - 1]
467
- end
468
- end
469
- end
470
- register 'erubis', ErubisTemplate
471
-
472
-
473
- # Haml template implementation. See:
474
- # http://haml.hamptoncatlin.com/
475
- class HamlTemplate < Template
476
- def initialize_engine
477
- return if defined? ::Haml::Engine
478
- require_template_library 'haml'
479
- end
480
-
481
- def prepare
482
- options = @options.merge(:filename => eval_file, :line => line)
483
- @engine = ::Haml::Engine.new(data, options)
484
- end
485
-
486
- def evaluate(scope, locals, &block)
487
- if @engine.respond_to?(:precompiled_method_return_value, true)
488
- super
489
- else
490
- @engine.render(scope, locals, &block)
491
- end
492
- end
493
-
494
- # Precompiled Haml source. Taken from the precompiled_with_ambles
495
- # method in Haml::Precompiler:
496
- # http://github.com/nex3/haml/blob/master/lib/haml/precompiler.rb#L111-126
497
- def precompiled_template(locals)
498
- @engine.precompiled
499
- end
500
-
501
- def precompiled_preamble(locals)
502
- local_assigns = super
503
- @engine.instance_eval do
504
- <<-RUBY
505
- begin
506
- extend Haml::Helpers
507
- _hamlout = @haml_buffer = Haml::Buffer.new(@haml_buffer, #{options_for_buffer.inspect})
508
- _erbout = _hamlout.buffer
509
- __in_erb_template = true
510
- _haml_locals = locals
511
- #{local_assigns}
512
- RUBY
513
- end
514
- end
515
-
516
- def precompiled_postamble(locals)
517
- @engine.instance_eval do
518
- <<-RUBY
519
- #{precompiled_method_return_value}
520
- ensure
521
- @haml_buffer = @haml_buffer.upper
522
- end
523
- RUBY
524
- end
525
- end
526
- end
527
- register 'haml', HamlTemplate
528
-
529
-
530
- # Sass template implementation. See:
531
- # http://haml.hamptoncatlin.com/
532
- #
533
- # Sass templates do not support object scopes, locals, or yield.
534
- class SassTemplate < Template
535
- def initialize_engine
536
- return if defined? ::Sass::Engine
537
- require_template_library 'sass'
538
- end
539
-
540
- def prepare
541
- @engine = ::Sass::Engine.new(data, sass_options)
542
- end
543
-
544
- def evaluate(scope, locals, &block)
545
- @output ||= @engine.render
546
- end
547
-
548
- private
549
- def sass_options
550
- options.merge(:filename => eval_file, :line => line, :syntax => :sass)
551
- end
552
- end
553
- register 'sass', SassTemplate
554
-
555
- # Sass's new .scss type template implementation.
556
- class ScssTemplate < SassTemplate
557
- private
558
- def sass_options
559
- options.merge(:filename => eval_file, :line => line, :syntax => :scss)
560
- end
561
- end
562
- register 'scss', ScssTemplate
563
-
564
- # Lessscss template implementation. See:
565
- # http://lesscss.org/
566
- #
567
- # Less templates do not support object scopes, locals, or yield.
568
- class LessTemplate < Template
569
- def initialize_engine
570
- return if defined? ::Less::Engine
571
- require_template_library 'less'
572
- end
573
-
574
- def prepare
575
- @engine = ::Less::Engine.new(data)
576
- end
577
-
578
- def evaluate(scope, locals, &block)
579
- @engine.to_css
580
- end
581
- end
582
- register 'less', LessTemplate
583
-
584
-
585
- # CoffeeScript template implementation. See:
586
- # http://coffeescript.org/
587
- #
588
- # CoffeeScript templates do not support object scopes, locals, or yield.
589
- class CoffeeScriptTemplate < Template
590
- @@default_no_wrap = false
591
-
592
- def self.default_no_wrap
593
- @@default_no_wrap
594
- end
595
-
596
- def self.default_no_wrap=(value)
597
- @@default_no_wrap = value
598
- end
599
-
600
- def initialize_engine
601
- return if defined? ::CoffeeScript
602
- require_template_library 'coffee_script'
603
- end
604
-
605
- def prepare
606
- @no_wrap = options.key?(:no_wrap) ? options[:no_wrap] :
607
- self.class.default_no_wrap
608
- end
609
-
610
- def evaluate(scope, locals, &block)
611
- @output ||= CoffeeScript.compile(data, :no_wrap => @no_wrap)
612
- end
613
- end
614
- register 'coffee', CoffeeScriptTemplate
615
-
616
-
617
- # Nokogiri template implementation. See:
618
- # http://nokogiri.org/
619
- class NokogiriTemplate < Template
620
- def initialize_engine
621
- return if defined?(::Nokogiri)
622
- require_template_library 'nokogiri'
623
- end
624
-
625
- def prepare; end
626
-
627
- def evaluate(scope, locals, &block)
628
- xml = ::Nokogiri::XML::Builder.new
629
- if data.respond_to?(:to_str)
630
- locals[:xml] = xml
631
- block &&= proc { yield.gsub(/^<\?xml version=\"1\.0\"\?>\n?/, "") }
632
- super(scope, locals, &block)
633
- elsif data.kind_of?(Proc)
634
- data.call(xml)
635
- end
636
- xml.to_xml
637
- end
638
-
639
- def precompiled_template(locals)
640
- data.to_str
641
- end
642
- end
643
- register 'nokogiri', NokogiriTemplate
644
-
645
- # Builder template implementation. See:
646
- # http://builder.rubyforge.org/
647
- class BuilderTemplate < Template
648
- def initialize_engine
649
- return if defined?(::Builder)
650
- require_template_library 'builder'
651
- end
652
-
653
- def prepare
654
- end
655
-
656
- def evaluate(scope, locals, &block)
657
- xml = ::Builder::XmlMarkup.new(:indent => 2)
658
- if data.respond_to?(:to_str)
659
- locals[:xml] = xml
660
- super(scope, locals, &block)
661
- elsif data.kind_of?(Proc)
662
- data.call(xml)
663
- end
664
- xml.target!
665
- end
666
-
667
- def precompiled_template(locals)
668
- data.to_str
669
- end
670
- end
671
- register 'builder', BuilderTemplate
672
-
673
-
674
- # Liquid template implementation. See:
675
- # http://liquid.rubyforge.org/
676
- #
677
- # Liquid is designed to be a *safe* template system and threfore
678
- # does not provide direct access to execuatable scopes. In order to
679
- # support a +scope+, the +scope+ must be able to represent itself
680
- # as a hash by responding to #to_h. If the +scope+ does not respond
681
- # to #to_h it will be ignored.
682
- #
683
- # LiquidTemplate does not support yield blocks.
684
- #
685
- # It's suggested that your program require 'liquid' at load
686
- # time when using this template engine.
687
- class LiquidTemplate < Template
688
- def initialize_engine
689
- return if defined? ::Liquid::Template
690
- require_template_library 'liquid'
691
- end
692
-
693
- def prepare
694
- @engine = ::Liquid::Template.parse(data)
695
- end
141
+ require 'tilt/erb'
142
+ register ERBTemplate, 'erb', 'rhtml'
143
+ register ErubisTemplate, 'erb', 'rhtml', 'erubis'
696
144
 
697
- def evaluate(scope, locals, &block)
698
- locals = locals.inject({}){ |h,(k,v)| h[k.to_s] = v ; h }
699
- if scope.respond_to?(:to_h)
700
- scope = scope.to_h.inject({}){ |h,(k,v)| h[k.to_s] = v ; h }
701
- locals = scope.merge(locals)
702
- end
703
- locals['yield'] = block.nil? ? '' : yield
704
- locals['content'] = locals['yield']
705
- @engine.render(locals)
706
- end
707
- end
708
- register 'liquid', LiquidTemplate
145
+ require 'tilt/haml'
146
+ register HamlTemplate, 'haml'
709
147
 
148
+ require 'tilt/css'
149
+ register SassTemplate, 'sass'
150
+ register ScssTemplate, 'scss'
151
+ register LessTemplate, 'less'
710
152
 
711
- # Discount Markdown implementation. See:
712
- # http://github.com/rtomayko/rdiscount
713
- #
714
- # RDiscount is a simple text filter. It does not support +scope+ or
715
- # +locals+. The +:smart+ and +:filter_html+ options may be set true
716
- # to enable those flags on the underlying RDiscount object.
717
- class RDiscountTemplate < Template
718
- def flags
719
- [:smart, :filter_html].select { |flag| options[flag] }
720
- end
153
+ require 'tilt/coffee'
154
+ register CoffeeScriptTemplate, 'coffee'
721
155
 
722
- def initialize_engine
723
- return if defined? ::RDiscount
724
- require_template_library 'rdiscount'
725
- end
156
+ require 'tilt/nokogiri'
157
+ register NokogiriTemplate, 'nokogiri'
726
158
 
727
- def prepare
728
- @engine = RDiscount.new(data, *flags)
729
- @output = nil
730
- end
159
+ require 'tilt/builder'
160
+ register BuilderTemplate, 'builder'
731
161
 
732
- def evaluate(scope, locals, &block)
733
- @output ||= @engine.to_html
734
- end
735
- end
736
- register 'markdown', RDiscountTemplate
737
- register 'mkd', RDiscountTemplate
738
- register 'md', RDiscountTemplate
162
+ require 'tilt/markaby'
163
+ register MarkabyTemplate, 'mab'
739
164
 
165
+ require 'tilt/liquid'
166
+ register LiquidTemplate, 'liquid'
740
167
 
741
- # BlueCloth Markdown implementation. See:
742
- # http://deveiate.org/projects/BlueCloth/
743
- #
744
- # RDiscount is a simple text filter. It does not support +scope+ or
745
- # +locals+. The +:smartypants+ and +:escape_html+ options may be set true
746
- # to enable those flags on the underlying BlueCloth object.
747
- class BlueClothTemplate < Template
748
- def initialize_engine
749
- return if defined? ::BlueCloth
750
- require_template_library 'bluecloth'
751
- end
168
+ require 'tilt/radius'
169
+ register RadiusTemplate, 'radius'
752
170
 
753
- def prepare
754
- @engine = BlueCloth.new(data, options)
755
- @output = nil
756
- end
757
-
758
- def evaluate(scope, locals, &block)
759
- @output ||= @engine.to_html
760
- end
761
- end
171
+ require 'tilt/markdown'
172
+ register MarukuTemplate, 'markdown', 'mkd', 'md'
173
+ register KramdownTemplate, 'markdown', 'mkd', 'md'
174
+ register BlueClothTemplate, 'markdown', 'mkd', 'md'
175
+ register RedcarpetTemplate, 'markdown', 'mkd', 'md'
176
+ register RDiscountTemplate, 'markdown', 'mkd', 'md'
762
177
 
178
+ require 'tilt/textile'
179
+ register RedClothTemplate, 'textile'
763
180
 
764
- # RedCloth implementation. See:
765
- # http://redcloth.org/
766
- class RedClothTemplate < Template
767
- def initialize_engine
768
- return if defined? ::RedCloth
769
- require_template_library 'redcloth'
770
- end
771
-
772
- def prepare
773
- @engine = RedCloth.new(data)
774
- @output = nil
775
- end
181
+ require 'tilt/rdoc'
182
+ register RDocTemplate, 'rdoc'
776
183
 
777
- def evaluate(scope, locals, &block)
778
- @output ||= @engine.to_html
779
- end
780
- end
781
- register 'textile', RedClothTemplate
782
-
783
-
784
- # RDoc template. See:
785
- # http://rdoc.rubyforge.org/
786
- #
787
- # It's suggested that your program require 'rdoc/markup' and
788
- # 'rdoc/markup/to_html' at load time when using this template
789
- # engine.
790
- class RDocTemplate < Template
791
- def initialize_engine
792
- return if defined?(::RDoc::Markup)
793
- require_template_library 'rdoc/markup'
794
- require_template_library 'rdoc/markup/to_html'
795
- end
796
-
797
- def prepare
798
- markup = RDoc::Markup::ToHtml.new
799
- @engine = markup.convert(data)
800
- @output = nil
801
- end
802
-
803
- def evaluate(scope, locals, &block)
804
- @output ||= @engine.to_s
805
- end
806
- end
807
- register 'rdoc', RDocTemplate
808
-
809
-
810
- # Radius Template
811
- # http://github.com/jlong/radius/
812
- class RadiusTemplate < Template
813
- def initialize_engine
814
- return if defined? ::Radius
815
- require_template_library 'radius'
816
- end
817
-
818
- def prepare
819
- end
820
-
821
- def evaluate(scope, locals, &block)
822
- context = Class.new(Radius::Context).new
823
- context.define_tag("yield") do
824
- block.call
825
- end
826
- locals.each do |tag, value|
827
- context.define_tag(tag) do
828
- value
829
- end
830
- end
831
- (class << context; self; end).class_eval do
832
- define_method :tag_missing do |tag, attr|
833
- scope.__send__(tag) # any way to support attr as args?
834
- end
835
- end
836
- options = {:tag_prefix => 'r'}.merge(@options)
837
- parser = Radius::Parser.new(context, options)
838
- parser.parse(data)
839
- end
840
- end
841
- register 'radius', RadiusTemplate
842
-
843
-
844
- # Markaby
845
- # http://github.com/markaby/markaby
846
- class MarkabyTemplate < Template
847
- def self.builder_class
848
- @builder_class ||= Class.new(Markaby::Builder) do
849
- def __capture_markaby_tilt__(&block)
850
- __run_markaby_tilt__ do
851
- text capture(&block)
852
- end
853
- end
854
- end
855
- end
856
-
857
- def initialize_engine
858
- return if defined? ::Markaby
859
- require_template_library 'markaby'
860
- end
861
-
862
- def prepare
863
- end
864
-
865
- def evaluate(scope, locals, &block)
866
- builder = self.class.builder_class.new({}, scope)
867
- builder.locals = locals
868
-
869
- if data.kind_of? Proc
870
- (class << builder; self end).send(:define_method, :__run_markaby_tilt__, &data)
871
- else
872
- builder.instance_eval <<-CODE, __FILE__, __LINE__
873
- def __run_markaby_tilt__
874
- #{data}
875
- end
876
- CODE
877
- end
878
-
879
- if block
880
- builder.__capture_markaby_tilt__(&block)
881
- else
882
- builder.__run_markaby_tilt__
883
- end
884
-
885
- builder.to_s
886
- end
887
- end
888
- register 'mab', MarkabyTemplate
184
+ require 'tilt/creole'
185
+ register CreoleTemplate, 'creole'
889
186
  end