tilt 2.0.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +5 -5
  2. data/COPYING +2 -1
  3. data/bin/tilt +2 -110
  4. data/lib/tilt/_emacs_org.rb +2 -0
  5. data/lib/tilt/_handlebars.rb +2 -0
  6. data/lib/tilt/_jbuilder.rb +2 -0
  7. data/lib/tilt/_org.rb +2 -0
  8. data/lib/tilt/asciidoc.rb +11 -23
  9. data/lib/tilt/babel.rb +8 -0
  10. data/lib/tilt/builder.rb +23 -14
  11. data/lib/tilt/cli.rb +134 -0
  12. data/lib/tilt/coffee.rb +17 -25
  13. data/lib/tilt/commonmarker.rb +95 -0
  14. data/lib/tilt/creole.rb +9 -20
  15. data/lib/tilt/csv.rb +9 -21
  16. data/lib/tilt/erb.rb +27 -19
  17. data/lib/tilt/erubi.rb +55 -0
  18. data/lib/tilt/erubis.rb +20 -12
  19. data/lib/tilt/etanni.rb +5 -4
  20. data/lib/tilt/haml.rb +79 -42
  21. data/lib/tilt/kramdown.rb +8 -28
  22. data/lib/tilt/liquid.rb +11 -9
  23. data/lib/tilt/livescript.rb +11 -0
  24. data/lib/tilt/mapping.rb +242 -95
  25. data/lib/tilt/markaby.rb +5 -7
  26. data/lib/tilt/maruku.rb +6 -18
  27. data/lib/tilt/nokogiri.rb +11 -10
  28. data/lib/tilt/pandoc.rb +39 -0
  29. data/lib/tilt/pipeline.rb +19 -0
  30. data/lib/tilt/plain.rb +4 -19
  31. data/lib/tilt/prawn.rb +28 -0
  32. data/lib/tilt/radius.rb +15 -22
  33. data/lib/tilt/rdiscount.rb +17 -33
  34. data/lib/tilt/rdoc.rb +14 -35
  35. data/lib/tilt/redcarpet.rb +20 -93
  36. data/lib/tilt/redcloth.rb +9 -19
  37. data/lib/tilt/rst-pandoc.rb +10 -0
  38. data/lib/tilt/sass.rb +59 -22
  39. data/lib/tilt/slim.rb +5 -0
  40. data/lib/tilt/string.rb +9 -3
  41. data/lib/tilt/template.rb +246 -78
  42. data/lib/tilt/typescript.rb +19 -0
  43. data/lib/tilt/wikicloth.rb +8 -18
  44. data/lib/tilt/yajl.rb +5 -11
  45. data/lib/tilt.rb +91 -41
  46. metadata +39 -102
  47. data/CHANGELOG.md +0 -61
  48. data/Gemfile +0 -39
  49. data/HACKING +0 -16
  50. data/README.md +0 -206
  51. data/Rakefile +0 -95
  52. data/docs/TEMPLATES.md +0 -523
  53. data/docs/common.css +0 -14
  54. data/lib/tilt/bluecloth.rb +0 -24
  55. data/lib/tilt/less.rb +0 -38
  56. data/test/markaby/locals.mab +0 -1
  57. data/test/markaby/markaby.mab +0 -1
  58. data/test/markaby/markaby_other_static.mab +0 -1
  59. data/test/markaby/render_twice.mab +0 -1
  60. data/test/markaby/scope.mab +0 -1
  61. data/test/markaby/yielding.mab +0 -2
  62. data/test/test_helper.rb +0 -64
  63. data/test/tilt_asciidoctor_test.rb +0 -44
  64. data/test/tilt_blueclothtemplate_test.rb +0 -33
  65. data/test/tilt_buildertemplate_test.rb +0 -59
  66. data/test/tilt_cache_test.rb +0 -32
  67. data/test/tilt_coffeescripttemplate_test.rb +0 -104
  68. data/test/tilt_compilesite_test.rb +0 -51
  69. data/test/tilt_creoletemplate_test.rb +0 -24
  70. data/test/tilt_csv_test.rb +0 -65
  71. data/test/tilt_erbtemplate_test.rb +0 -239
  72. data/test/tilt_erubistemplate_test.rb +0 -151
  73. data/test/tilt_etannitemplate_test.rb +0 -174
  74. data/test/tilt_hamltemplate_test.rb +0 -144
  75. data/test/tilt_kramdown_test.rb +0 -20
  76. data/test/tilt_lesstemplate_test.less +0 -1
  77. data/test/tilt_lesstemplate_test.rb +0 -42
  78. data/test/tilt_liquidtemplate_test.rb +0 -78
  79. data/test/tilt_mapping_test.rb +0 -229
  80. data/test/tilt_markaby_test.rb +0 -88
  81. data/test/tilt_markdown_test.rb +0 -174
  82. data/test/tilt_marukutemplate_test.rb +0 -36
  83. data/test/tilt_metadata_test.rb +0 -42
  84. data/test/tilt_nokogiritemplate_test.rb +0 -87
  85. data/test/tilt_radiustemplate_test.rb +0 -75
  86. data/test/tilt_rdiscounttemplate_test.rb +0 -43
  87. data/test/tilt_rdoctemplate_test.rb +0 -29
  88. data/test/tilt_redcarpettemplate_test.rb +0 -59
  89. data/test/tilt_redclothtemplate_test.rb +0 -36
  90. data/test/tilt_sasstemplate_test.rb +0 -41
  91. data/test/tilt_stringtemplate_test.rb +0 -171
  92. data/test/tilt_template_test.rb +0 -316
  93. data/test/tilt_test.rb +0 -60
  94. data/test/tilt_wikiclothtemplate_test.rb +0 -32
  95. data/test/tilt_yajltemplate_test.rb +0 -101
  96. data/tilt.gemspec +0 -107
data/lib/tilt/mapping.rb CHANGED
@@ -1,4 +1,81 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'pipeline'
3
+
1
4
  module Tilt
5
+ # Private internal base class for both Mapping and FinalizedMapping, for the shared methods.
6
+ class BaseMapping
7
+ # Instantiates a new template class based on the file.
8
+ #
9
+ # @raise [RuntimeError] if there is no template class registered for the
10
+ # file name.
11
+ #
12
+ # @example
13
+ # mapping.new('index.mt') # => instance of MyEngine::Template
14
+ #
15
+ # @see Tilt::Template.new
16
+ def new(file, line=nil, options={}, &block)
17
+ if template_class = self[file]
18
+ template_class.new(file, line, options, &block)
19
+ else
20
+ fail "No template engine registered for #{File.basename(file)}"
21
+ end
22
+ end
23
+
24
+ # Looks up a template class based on file name and/or extension.
25
+ #
26
+ # @example
27
+ # mapping['views/hello.erb'] # => Tilt::ERBTemplate
28
+ # mapping['hello.erb'] # => Tilt::ERBTemplate
29
+ # mapping['erb'] # => Tilt::ERBTemplate
30
+ #
31
+ # @return [template class]
32
+ def [](file)
33
+ _, ext = split(file)
34
+ ext && lookup(ext)
35
+ end
36
+
37
+ alias template_for []
38
+
39
+ # Looks up a list of template classes based on file name. If the file name
40
+ # has multiple extensions, it will return all template classes matching the
41
+ # extensions from the end.
42
+ #
43
+ # @example
44
+ # mapping.templates_for('views/index.haml.erb')
45
+ # # => [Tilt::ERBTemplate, Tilt::HamlTemplate]
46
+ #
47
+ # @return [Array<template class>]
48
+ def templates_for(file)
49
+ templates = []
50
+
51
+ while true
52
+ prefix, ext = split(file)
53
+ break unless ext
54
+ templates << lookup(ext)
55
+ file = prefix
56
+ end
57
+
58
+ templates
59
+ end
60
+
61
+ private
62
+
63
+ def split(file)
64
+ pattern = file.to_s.downcase
65
+ full_pattern = pattern.dup
66
+
67
+ until registered?(pattern)
68
+ return if pattern.empty?
69
+ pattern = File.basename(pattern)
70
+ pattern.sub!(/\A[^.]*\.?/, '')
71
+ end
72
+
73
+ prefix_size = full_pattern.size - pattern.size
74
+ [full_pattern[0,prefix_size-1], pattern]
75
+ end
76
+ end
77
+ private_constant :BaseMapping
78
+
2
79
  # Tilt::Mapping associates file extensions with template implementations.
3
80
  #
4
81
  # mapping = Tilt::Mapping.new
@@ -36,16 +113,18 @@ module Tilt
36
113
  # the exception of the first, since that was the most preferred one.
37
114
  #
38
115
  # mapping = Tilt::Mapping.new
39
- # mapping.register_lazy('Bluecloth::Template', 'bluecloth/template', 'md')
116
+ # mapping.register_lazy('Maruku::Template', 'maruku/template', 'md')
40
117
  # mapping.register_lazy('RDiscount::Template', 'rdiscount/template', 'md')
41
118
  # mapping['index.md']
42
119
  # # => RDiscount::Template
43
120
  #
44
121
  # In the previous example we say that RDiscount has a *higher priority* than
45
- # BlueCloth. Tilt will first try to `require "rdiscount/template"`, falling
46
- # back to `require "bluecloth/template"`. If none of these are successful,
122
+ # Maruku. Tilt will first try to `require "rdiscount/template"`, falling
123
+ # back to `require "maruku/template"`. If none of these are successful,
47
124
  # the first error will be raised.
48
- class Mapping
125
+ class Mapping < BaseMapping
126
+ LOCK = Mutex.new
127
+
49
128
  # @private
50
129
  attr_reader :lazy_map, :template_map
51
130
 
@@ -56,11 +135,29 @@ module Tilt
56
135
 
57
136
  # @private
58
137
  def initialize_copy(other)
59
- @template_map = other.template_map.dup
60
- @lazy_map = other.lazy_map.dup
138
+ LOCK.synchronize do
139
+ @template_map = other.template_map.dup
140
+ @lazy_map = other.lazy_map.dup
141
+ end
142
+ end
143
+
144
+ # Return a finalized mapping. A finalized mapping will only include
145
+ # support for template libraries already loaded, and will not
146
+ # allow registering new template libraries or lazy loading template
147
+ # libraries not yet loaded. Finalized mappings improve performance
148
+ # by not requiring synchronization and ensure that the mapping will
149
+ # not attempt to load additional files (useful when restricting
150
+ # file system access after template libraries in use are loaded).
151
+ def finalized
152
+ LOCK.synchronize{@lazy_map.dup}.each do |pattern, classes|
153
+ register_defined_classes(LOCK.synchronize{classes.map(&:first)}, pattern)
154
+ end
155
+
156
+ # Check if a template class is already present
157
+ FinalizedMapping.new(LOCK.synchronize{@template_map.dup}.freeze)
61
158
  end
62
159
 
63
- # Registrers a lazy template implementation by file extension. You
160
+ # Registers a lazy template implementation by file extension. You
64
161
  # can have multiple lazy template implementations defined on the
65
162
  # same file extension, in which case the template implementation
66
163
  # defined *last* will be attempted loaded *first*.
@@ -83,8 +180,9 @@ module Tilt
83
180
  class_name = "Tilt::#{class_name}"
84
181
  end
85
182
 
183
+ v = [class_name, file].freeze
86
184
  extensions.each do |ext|
87
- @lazy_map[ext].unshift([class_name, file])
185
+ LOCK.synchronize{@lazy_map[ext].unshift(v)}
88
186
  end
89
187
  end
90
188
 
@@ -106,86 +204,95 @@ module Tilt
106
204
  end
107
205
 
108
206
  extensions.each do |ext|
109
- @template_map[ext.to_s] = template_class
207
+ ext = ext.to_s
208
+ LOCK.synchronize do
209
+ @template_map[ext] = template_class
210
+ end
110
211
  end
111
212
  end
112
213
 
113
- # Checks if a file extension is registered (either eagerly or
114
- # lazily) in this mapping.
214
+ # Register a new template class using the given extension that
215
+ # represents a pipeline of multiple existing template, where the
216
+ # output from the previous template is used as input to the next
217
+ # template.
115
218
  #
116
- # @param ext [String] File extension.
219
+ # This will register a template class that processes the input
220
+ # with the *erb* template processor, and takes the output of
221
+ # that and feeds it to the *scss* template processor, returning
222
+ # the output of the *scss* template processor as the result of
223
+ # the pipeline.
224
+ #
225
+ # @param ext [String] Primary extension to register
226
+ # @option :templates [Array<String>] Extensions of templates
227
+ # to execute in order (defaults to the ext.split('.').reverse)
228
+ # @option :extra_exts [Array<String>] Additional extensions to register
229
+ # @option String [Hash] Options hash for individual template in the
230
+ # pipeline (key is extension).
231
+ # @return [void]
117
232
  #
118
233
  # @example
119
- # mapping.registered?('erb') # => true
120
- # mapping.registered?('nope') # => false
121
- def registered?(ext)
122
- @template_map.has_key?(ext.downcase) or lazy?(ext)
234
+ # mapping.register_pipeline('scss.erb')
235
+ # mapping.register_pipeline('scss.erb', 'erb'=>{:outvar=>'@foo'})
236
+ # mapping.register_pipeline('scsserb', :extra_exts => 'scss.erb',
237
+ # :templates=>['erb', 'scss'])
238
+ def register_pipeline(ext, options=EMPTY_HASH)
239
+ templates = options[:templates] || ext.split('.').reverse
240
+ templates = templates.map{|t| [self[t], options[t] || EMPTY_HASH]}
241
+
242
+ klass = Class.new(Pipeline)
243
+ klass.send(:const_set, :TEMPLATES, templates)
244
+
245
+ register(klass, ext, *Array(options[:extra_exts]))
246
+ klass
123
247
  end
124
248
 
125
- # Instantiates a new template class based on the file.
249
+ # Unregisters an extension. This removes the both normal registrations
250
+ # and lazy registrations.
126
251
  #
127
- # @raise [RuntimeError] if there is no template class registered for the
128
- # file name.
252
+ # @param extensions [Array<String>] List of extensions.
253
+ # @return nil
129
254
  #
130
255
  # @example
131
- # mapping.new('index.mt') # => instance of MyEngine::Template
132
- #
133
- # @see Tilt::Template.new
134
- def new(file, line=nil, options={}, &block)
135
- if template_class = self[file]
136
- template_class.new(file, line, options, &block)
137
- else
138
- fail "No template engine registered for #{File.basename(file)}"
256
+ # mapping.register MyEngine::Template, 'mt'
257
+ # mapping['index.mt'] # => MyEngine::Template
258
+ # mapping.unregister('mt')
259
+ # mapping['index.mt'] # => nil
260
+ def unregister(*extensions)
261
+ extensions.each do |ext|
262
+ ext = ext.to_s
263
+ LOCK.synchronize do
264
+ @template_map.delete(ext)
265
+ @lazy_map.delete(ext)
266
+ end
139
267
  end
140
- end
141
268
 
142
- # Looks up a template class based on file name and/or extension.
143
- #
144
- # @example
145
- # mapping['views/hello.erb'] # => Tilt::ERBTemplate
146
- # mapping['hello.erb'] # => Tilt::ERBTemplate
147
- # mapping['erb'] # => Tilt::ERBTemplate
148
- #
149
- # @return [template class]
150
- def [](file)
151
- prefix, ext = split(file)
152
- ext && lookup(ext)
269
+ nil
153
270
  end
154
271
 
155
- alias template_for []
156
-
157
- # Looks up a list of template classes based on file name. If the file name
158
- # has multiple extensions, it will return all template classes matching the
159
- # extensions from the end.
272
+ # Checks if a file extension is registered (either eagerly or
273
+ # lazily) in this mapping.
160
274
  #
161
- # @example
162
- # mapping.templates_for('views/index.haml.erb')
163
- # # => [Tilt::ERBTemplate, Tilt::HamlTemplate]
275
+ # @param ext [String] File extension.
164
276
  #
165
- # @return [Array<template class>]
166
- def templates_for(file)
167
- templates = []
168
-
169
- while true
170
- prefix, ext = split(file)
171
- break unless ext
172
- templates << lookup(ext)
173
- file = prefix
174
- end
175
-
176
- templates
277
+ # @example
278
+ # mapping.registered?('erb') # => true
279
+ # mapping.registered?('nope') # => false
280
+ def registered?(ext)
281
+ ext_downcase = ext.downcase
282
+ LOCK.synchronize{@template_map.has_key?(ext_downcase)} or lazy?(ext)
177
283
  end
178
284
 
179
285
  # Finds the extensions the template class has been registered under.
180
286
  # @param [template class] template_class
181
287
  def extensions_for(template_class)
182
288
  res = []
183
- template_map.each do |ext, klass|
289
+ LOCK.synchronize{@template_map.to_a}.each do |ext, klass|
184
290
  res << ext if template_class == klass
185
291
  end
186
- lazy_map.each do |ext, choices|
187
- res << ext if choices.any? { |klass, file| template_class.to_s == klass }
292
+ LOCK.synchronize{@lazy_map.to_a}.each do |ext, choices|
293
+ res << ext if LOCK.synchronize{choices.dup}.any? { |klass, file| template_class.to_s == klass }
188
294
  end
295
+ res.uniq!
189
296
  res
190
297
  end
191
298
 
@@ -193,40 +300,30 @@ module Tilt
193
300
 
194
301
  def lazy?(ext)
195
302
  ext = ext.downcase
196
- @lazy_map.has_key?(ext) && !@lazy_map[ext].empty?
197
- end
198
-
199
- def split(file)
200
- pattern = file.to_s.downcase
201
- full_pattern = pattern.dup
202
-
203
- until registered?(pattern)
204
- return if pattern.empty?
205
- pattern = File.basename(pattern)
206
- pattern.sub!(/^[^.]*\.?/, '')
207
- end
208
-
209
- prefix_size = full_pattern.size - pattern.size
210
- [full_pattern[0,prefix_size-1], pattern]
303
+ LOCK.synchronize{@lazy_map.has_key?(ext) && !@lazy_map[ext].empty?}
211
304
  end
212
305
 
213
306
  def lookup(ext)
214
- @template_map[ext] || lazy_load(ext)
307
+ LOCK.synchronize{@template_map[ext]} || lazy_load(ext)
215
308
  end
216
309
 
217
- def lazy_load(pattern)
218
- return unless @lazy_map.has_key?(pattern)
219
-
220
- choices = @lazy_map[pattern]
221
-
222
- # Check if a template class is already present
223
- choices.each do |class_name, file|
310
+ def register_defined_classes(class_names, pattern)
311
+ class_names.each do |class_name|
224
312
  template_class = constant_defined?(class_name)
225
313
  if template_class
226
314
  register(template_class, pattern)
227
- return template_class
315
+ yield template_class if block_given?
228
316
  end
229
317
  end
318
+ end
319
+
320
+ def lazy_load(pattern)
321
+ choices = LOCK.synchronize{@lazy_map[pattern].dup}
322
+
323
+ # Check if a template class is already present
324
+ register_defined_classes(choices.map(&:first), pattern) do |template_class|
325
+ return template_class
326
+ end
230
327
 
231
328
  first_failure = nil
232
329
 
@@ -234,12 +331,6 @@ module Tilt
234
331
  choices.each do |class_name, file|
235
332
  begin
236
333
  require file
237
-
238
- if Thread.list.size > 1
239
- warn "WARN: tilt autoloading '#{file}' in a non thread-safe way; " +
240
- "explicit require '#{file}' suggested."
241
- end
242
-
243
334
  # It's safe to eval() here because constant_defined? will
244
335
  # raise NameError on invalid constant names
245
336
  template_class = eval(class_name)
@@ -251,15 +342,71 @@ module Tilt
251
342
  end
252
343
  end
253
344
 
254
- raise first_failure if first_failure
345
+ raise first_failure
255
346
  end
256
347
 
348
+ # The proper behavior (in MRI) for autoload? is to
349
+ # return `false` when the constant/file has been
350
+ # explicitly required.
351
+ #
352
+ # However, in JRuby it returns `true` even after it's
353
+ # been required. In that case it turns out that `defined?`
354
+ # returns `"constant"` if it exists and `nil` when it doesn't.
355
+ # This is actually a second bug: `defined?` should resolve
356
+ # autoload (aka. actually try to require the file).
357
+ #
358
+ # We use the second bug in order to resolve the first bug.
359
+
257
360
  def constant_defined?(name)
258
361
  name.split('::').inject(Object) do |scope, n|
259
- return false unless scope.const_defined?(n)
260
- return false if scope.autoload?(n) # skip autload
362
+ return false if scope.autoload?(n) || !scope.const_defined?(n)
261
363
  scope.const_get(n)
262
364
  end
263
365
  end
264
366
  end
367
+
368
+ # Private internal class for finalized mappings, which are frozen and
369
+ # cannot be modified.
370
+ class FinalizedMapping < BaseMapping
371
+ # Set the template map to use. The template map should already
372
+ # be frozen, but this is an internal class, so it does not
373
+ # explicitly check for that.
374
+ def initialize(template_map)
375
+ @template_map = template_map
376
+ freeze
377
+ end
378
+
379
+ # Returns receiver, since instances are always frozen.
380
+ def dup
381
+ self
382
+ end
383
+
384
+ # Returns receiver, since instances are always frozen.
385
+ def clone(freeze: false)
386
+ self
387
+ end
388
+
389
+ # Return whether the given file extension has been registered.
390
+ def registered?(ext)
391
+ @template_map.has_key?(ext.downcase)
392
+ end
393
+
394
+ # Returns an aarry of all extensions the template class will
395
+ # be used for.
396
+ def extensions_for(template_class)
397
+ res = []
398
+ @template_map.each do |ext, klass|
399
+ res << ext if template_class == klass
400
+ end
401
+ res.uniq!
402
+ res
403
+ end
404
+
405
+ private
406
+
407
+ def lookup(ext)
408
+ @template_map[ext]
409
+ end
410
+ end
411
+ private_constant :FinalizedMapping
265
412
  end
data/lib/tilt/markaby.rb CHANGED
@@ -1,4 +1,5 @@
1
- require 'tilt/template'
1
+ # frozen_string_literal: true
2
+ require_relative 'template'
2
3
  require 'markaby'
3
4
 
4
5
  module Tilt
@@ -15,19 +16,16 @@ module Tilt
15
16
  end
16
17
  end
17
18
 
18
- def prepare
19
- end
20
-
21
19
  def evaluate(scope, locals, &block)
22
20
  builder = self.class.builder_class.new({}, scope)
23
21
  builder.locals = locals
24
22
 
25
- if data.kind_of? Proc
26
- (class << builder; self end).send(:define_method, :__run_markaby_tilt__, &data)
23
+ if @data.kind_of? Proc
24
+ (class << builder; self end).send(:define_method, :__run_markaby_tilt__, &@data)
27
25
  else
28
26
  builder.instance_eval <<-CODE, __FILE__, __LINE__
29
27
  def __run_markaby_tilt__
30
- #{data}
28
+ #{@data}
31
29
  end
32
30
  CODE
33
31
  end
data/lib/tilt/maruku.rb CHANGED
@@ -1,22 +1,10 @@
1
- require 'tilt/template'
1
+ # frozen_string_literal: true
2
+ require_relative 'template'
2
3
  require 'maruku'
3
4
 
4
- module Tilt
5
- # Maruku markdown implementation. See:
6
- # http://maruku.rubyforge.org/
7
- class MarukuTemplate < Template
8
- def prepare
9
- @engine = Maruku.new(data, options)
10
- @output = nil
11
- end
5
+ warn 'tilt/maruku is deprecated, as maruku requires modifying string literals', uplevel: 1
12
6
 
13
- def evaluate(scope, locals, &block)
14
- @output ||= @engine.to_html
15
- end
16
-
17
- def allows_script?
18
- false
19
- end
20
- end
7
+ # Maruku markdown implementation. See: https://github.com/bhollis/maruku
8
+ Tilt::MarukuTemplate = Tilt::StaticTemplate.subclass do
9
+ Maruku.new(@data, @options).to_html
21
10
  end
22
-
data/lib/tilt/nokogiri.rb CHANGED
@@ -1,21 +1,23 @@
1
- require 'tilt/template'
1
+ # frozen_string_literal: true
2
+ require_relative 'template'
2
3
  require 'nokogiri'
3
4
 
4
5
  module Tilt
5
6
  # Nokogiri template implementation. See:
6
7
  # http://nokogiri.org/
7
8
  class NokogiriTemplate < Template
8
- DOCUMENT_HEADER = /^<\?xml version=\"1\.0\"\?>\n?/
9
+ DOCUMENT_HEADER = /\A<\?xml version=\"1\.0\"\?>\n?/
9
10
  self.default_mime_type = 'text/xml'
10
11
 
11
- def prepare; end
12
-
13
12
  def evaluate(scope, locals)
14
- if data.respond_to?(:to_str)
15
- wrapper = proc { yield.sub(DOCUMENT_HEADER, "") } if block_given?
16
- super(scope, locals, &wrapper)
13
+ if @data.respond_to?(:to_str)
14
+ if block_given?
15
+ super(scope, locals){yield.sub(DOCUMENT_HEADER, "")}
16
+ else
17
+ super
18
+ end
17
19
  else
18
- ::Nokogiri::XML::Builder.new.tap(&data).to_xml
20
+ ::Nokogiri::XML::Builder.new(&@data).to_xml
19
21
  end
20
22
  end
21
23
 
@@ -29,8 +31,7 @@ module Tilt
29
31
  end
30
32
 
31
33
  def precompiled_template(locals)
32
- data.to_str
34
+ @data.to_str
33
35
  end
34
36
  end
35
37
  end
36
-
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'template'
3
+ require 'pandoc-ruby'
4
+
5
+ # Pandoc markdown implementation. See: http://pandoc.org/
6
+ Tilt::PandocTemplate = Tilt::StaticTemplate.subclass do
7
+ # turn options hash into an array
8
+ # Map tilt options to pandoc options
9
+ # Replace hash keys with value true with symbol for key
10
+ # Remove hash keys with value false
11
+ # Leave other hash keys untouched
12
+ pandoc_options = []
13
+ from = "markdown"
14
+ smart_extension = "-smart"
15
+ @options.each do |k,v|
16
+ case k
17
+ when :smartypants
18
+ smart_extension = "+smart" if v
19
+ when :escape_html
20
+ from = "markdown-raw_html" if v
21
+ when :commonmark
22
+ from = "commonmark" if v
23
+ when :markdown_strict
24
+ from = "markdown_strict" if v
25
+ else
26
+ case v
27
+ when true
28
+ pandoc_options << k
29
+ when false
30
+ # do nothing
31
+ else
32
+ pandoc_options << { k => v }
33
+ end
34
+ end
35
+ end
36
+ pandoc_options << { :f => from + smart_extension }
37
+
38
+ PandocRuby.new(@data, *pandoc_options).to_html.strip
39
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'template'
3
+
4
+ module Tilt
5
+ # Superclass used for pipeline templates. Should not be used directly.
6
+ class Pipeline < Template
7
+ def prepare
8
+ @pipeline = self.class::TEMPLATES.inject(proc{|*| data}) do |data, (klass, options)|
9
+ proc do |s,l,&sb|
10
+ klass.new(file, line, options, &proc{|*| data.call(s, l, &sb)}).render(s, l, &sb)
11
+ end
12
+ end
13
+ end
14
+
15
+ def evaluate(scope, locals, &block)
16
+ @pipeline.call(scope, locals, &block)
17
+ end
18
+ end
19
+ end
data/lib/tilt/plain.rb CHANGED
@@ -1,20 +1,5 @@
1
- require 'tilt/template'
1
+ # frozen_string_literal: true
2
+ require_relative 'template'
2
3
 
3
-
4
- module Tilt
5
- # Raw text (no template functionality).
6
- class PlainTemplate < Template
7
- self.default_mime_type = 'text/html'
8
-
9
- def self.engine_initialized?
10
- true
11
- end
12
-
13
- def prepare
14
- end
15
-
16
- def evaluate(scope, locals, &block)
17
- @output ||= data
18
- end
19
- end
20
- end
4
+ # Raw text (no template functionality).
5
+ Tilt::PlainTemplate = Tilt::StaticTemplate.subclass{@data}
data/lib/tilt/prawn.rb ADDED
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'template'
3
+ require 'prawn'
4
+
5
+ module Tilt
6
+ # Prawn template implementation. See: http://prawnpdf.org
7
+ class PrawnTemplate < Template
8
+ self.default_mime_type = 'application/pdf'
9
+
10
+ def prepare
11
+ @options[:page_size] = 'A4' unless @options.has_key?(:page_size)
12
+ @options[:page_layout] = :portrait unless @options.has_key?(:page_layout)
13
+ @engine = ::Prawn::Document.new(@options)
14
+ end
15
+
16
+ def evaluate(scope, locals, &block)
17
+ pdf = @engine
18
+ locals = locals.dup
19
+ locals[:pdf] = pdf
20
+ super
21
+ pdf.render
22
+ end
23
+
24
+ def precompiled_template(locals)
25
+ @data.to_str
26
+ end
27
+ end
28
+ end