tilt 1.4.1 → 2.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +1 -1
  3. data/bin/tilt +18 -8
  4. data/lib/tilt/asciidoc.rb +1 -8
  5. data/lib/tilt/babel.rb +16 -0
  6. data/lib/tilt/bluecloth.rb +24 -0
  7. data/lib/tilt/builder.rb +12 -15
  8. data/lib/tilt/coffee.rb +10 -6
  9. data/lib/tilt/commonmarker.rb +88 -0
  10. data/lib/tilt/creole.rb +25 -0
  11. data/lib/tilt/csv.rb +12 -18
  12. data/lib/tilt/dummy.rb +3 -0
  13. data/lib/tilt/erb.rb +9 -56
  14. data/lib/tilt/erubi.rb +32 -0
  15. data/lib/tilt/erubis.rb +43 -0
  16. data/lib/tilt/haml.rb +66 -44
  17. data/lib/tilt/kramdown.rb +25 -0
  18. data/lib/tilt/less.rb +30 -0
  19. data/lib/tilt/liquid.rb +9 -10
  20. data/lib/tilt/livescript.rb +23 -0
  21. data/lib/tilt/mapping.rb +293 -0
  22. data/lib/tilt/markaby.rb +1 -8
  23. data/lib/tilt/maruku.rb +22 -0
  24. data/lib/tilt/nokogiri.rb +1 -8
  25. data/lib/tilt/pandoc.rb +57 -0
  26. data/lib/tilt/plain.rb +0 -4
  27. data/lib/tilt/prawn.rb +43 -0
  28. data/lib/tilt/radius.rb +1 -8
  29. data/lib/tilt/rdiscount.rb +39 -0
  30. data/lib/tilt/rdoc.rb +3 -10
  31. data/lib/tilt/redcarpet.rb +86 -0
  32. data/lib/tilt/{textile.rb → redcloth.rb} +1 -8
  33. data/lib/tilt/rst-pandoc.rb +23 -0
  34. data/lib/tilt/sass.rb +78 -0
  35. data/lib/tilt/sigil.rb +34 -0
  36. data/lib/tilt/string.rb +1 -1
  37. data/lib/tilt/template.rb +121 -105
  38. data/lib/tilt/typescript.rb +26 -0
  39. data/lib/tilt/wikicloth.rb +22 -0
  40. data/lib/tilt/yajl.rb +1 -8
  41. data/lib/tilt.rb +118 -155
  42. metadata +38 -469
  43. data/CHANGELOG.md +0 -44
  44. data/Gemfile +0 -32
  45. data/HACKING +0 -16
  46. data/README.md +0 -232
  47. data/Rakefile +0 -104
  48. data/TEMPLATES.md +0 -516
  49. data/lib/tilt/css.rb +0 -80
  50. data/lib/tilt/markdown.rb +0 -214
  51. data/lib/tilt/wiki.rb +0 -58
  52. data/test/contest.rb +0 -68
  53. data/test/markaby/locals.mab +0 -1
  54. data/test/markaby/markaby.mab +0 -1
  55. data/test/markaby/markaby_other_static.mab +0 -1
  56. data/test/markaby/render_twice.mab +0 -1
  57. data/test/markaby/scope.mab +0 -1
  58. data/test/markaby/yielding.mab +0 -2
  59. data/test/tilt_asciidoctor_test.rb +0 -44
  60. data/test/tilt_blueclothtemplate_test.rb +0 -45
  61. data/test/tilt_buildertemplate_test.rb +0 -59
  62. data/test/tilt_cache_test.rb +0 -32
  63. data/test/tilt_coffeescripttemplate_test.rb +0 -114
  64. data/test/tilt_compilesite_test.rb +0 -51
  65. data/test/tilt_creoletemplate_test.rb +0 -28
  66. data/test/tilt_csv_test.rb +0 -69
  67. data/test/tilt_erbtemplate_test.rb +0 -239
  68. data/test/tilt_erubistemplate_test.rb +0 -151
  69. data/test/tilt_etannitemplate_test.rb +0 -173
  70. data/test/tilt_fallback_test.rb +0 -122
  71. data/test/tilt_hamltemplate_test.rb +0 -144
  72. data/test/tilt_kramdown_test.rb +0 -42
  73. data/test/tilt_lesstemplate_test.less +0 -1
  74. data/test/tilt_lesstemplate_test.rb +0 -42
  75. data/test/tilt_liquidtemplate_test.rb +0 -78
  76. data/test/tilt_markaby_test.rb +0 -88
  77. data/test/tilt_markdown_test.rb +0 -172
  78. data/test/tilt_marukutemplate_test.rb +0 -48
  79. data/test/tilt_nokogiritemplate_test.rb +0 -87
  80. data/test/tilt_radiustemplate_test.rb +0 -75
  81. data/test/tilt_rdiscounttemplate_test.rb +0 -55
  82. data/test/tilt_rdoctemplate_test.rb +0 -31
  83. data/test/tilt_redcarpettemplate_test.rb +0 -71
  84. data/test/tilt_redclothtemplate_test.rb +0 -36
  85. data/test/tilt_sasstemplate_test.rb +0 -41
  86. data/test/tilt_stringtemplate_test.rb +0 -170
  87. data/test/tilt_template_test.rb +0 -323
  88. data/test/tilt_test.rb +0 -65
  89. data/test/tilt_wikiclothtemplate_test.rb +0 -32
  90. data/test/tilt_yajltemplate_test.rb +0 -101
  91. data/tilt.gemspec +0 -120
data/lib/tilt/template.rb CHANGED
@@ -1,5 +1,19 @@
1
+ require 'thread'
2
+
1
3
  module Tilt
2
- TOPOBJECT = Object.superclass || Object
4
+ # @private
5
+ TOPOBJECT = if RUBY_VERSION >= '2.0'
6
+ # @private
7
+ module CompiledTemplates
8
+ self
9
+ end
10
+ elsif RUBY_VERSION >= '1.9'
11
+ BasicObject
12
+ else
13
+ Object
14
+ end
15
+ # @private
16
+ LOCK = Mutex.new
3
17
 
4
18
  # Base class for template implementations. Subclasses must implement
5
19
  # the #prepare method and one of the #evaluate or #precompiled_template
@@ -19,14 +33,22 @@ module Tilt
19
33
  # interface.
20
34
  attr_reader :options
21
35
 
22
- # Used to determine if this class's initialize_engine method has
23
- # been called yet.
24
- @engine_initialized = false
25
36
  class << self
26
- attr_accessor :engine_initialized
27
- alias engine_initialized? engine_initialized
37
+ # An empty Hash that the template engine can populate with various
38
+ # metadata.
39
+ def metadata
40
+ @metadata ||= {}
41
+ end
42
+
43
+ # @deprecated Use `.metadata[:mime_type]` instead.
44
+ def default_mime_type
45
+ metadata[:mime_type]
46
+ end
28
47
 
29
- attr_accessor :default_mime_type
48
+ # @deprecated Use `.metadata[:mime_type] = val` instead.
49
+ def default_mime_type=(value)
50
+ metadata[:mime_type] = value
51
+ end
30
52
  end
31
53
 
32
54
  # Create a new template with the file, line, and options specified. By
@@ -44,19 +66,14 @@ module Tilt
44
66
  when arg.respond_to?(:to_int) ; @line = arg.to_int
45
67
  when arg.respond_to?(:to_hash) ; @options = arg.to_hash.dup
46
68
  when arg.respond_to?(:path) ; @file = arg.path
47
- else raise TypeError
69
+ when arg.respond_to?(:to_path) ; @file = arg.to_path
70
+ else raise TypeError, "Can't load the template file. Pass a string with a path " +
71
+ "or an object that responds to 'to_str', 'path' or 'to_path'"
48
72
  end
49
73
  end
50
74
 
51
75
  raise ArgumentError, "file or block required" if (@file || block).nil?
52
76
 
53
- # call the initialize_engine method if this is the very first time
54
- # an instance of this class has been created.
55
- if !self.class.engine_initialized?
56
- initialize_engine
57
- self.class.engine_initialized = true
58
- end
59
-
60
77
  # used to hold compiled template methods
61
78
  @compiled_method = {}
62
79
 
@@ -69,7 +86,10 @@ module Tilt
69
86
  @data = @reader.call(self)
70
87
 
71
88
  if @data.respond_to?(:force_encoding)
72
- @data.force_encoding(default_encoding) if default_encoding
89
+ if default_encoding
90
+ @data = @data.dup if @data.frozen?
91
+ @data.force_encoding(default_encoding)
92
+ end
73
93
 
74
94
  if !@data.valid_encoding?
75
95
  raise Encoding::InvalidByteSequenceError, "#{eval_file} is not valid #{@data.encoding}"
@@ -79,28 +99,16 @@ module Tilt
79
99
  prepare
80
100
  end
81
101
 
82
- # The encoding of the source data. Defaults to the
83
- # default_encoding-option if present. You may override this method
84
- # in your template class if you have a better hint of the data's
85
- # encoding.
86
- def default_encoding
87
- @default_encoding
88
- end
89
-
90
- def read_template_file
91
- data = File.open(file, 'rb') { |io| io.read }
92
- if data.respond_to?(:force_encoding)
93
- # Set it to the default external (without verifying)
94
- data.force_encoding(Encoding.default_external) if Encoding.default_external
95
- end
96
- data
97
- end
98
-
99
102
  # Render the template in the given scope with the locals specified. If a
100
103
  # block is given, it is typically available within the template via
101
104
  # +yield+.
102
- def render(scope=Object.new, locals={}, &block)
103
- evaluate scope, locals || {}, &block
105
+ def render(scope=nil, locals={}, &block)
106
+ scope ||= Object.new
107
+ current_template = Thread.current[:tilt_current_template]
108
+ Thread.current[:tilt_current_template] = self
109
+ evaluate(scope, locals || {}, &block)
110
+ ensure
111
+ Thread.current[:tilt_current_template] = current_template
104
112
  end
105
113
 
106
114
  # The basename of the template file.
@@ -118,30 +126,26 @@ module Tilt
118
126
  file || '(__TEMPLATE__)'
119
127
  end
120
128
 
121
- # Whether or not this template engine allows executing Ruby script
122
- # within the template. If this is false, +scope+ and +locals+ will
123
- # generally not be used, nor will the provided block be avaiable
124
- # via +yield+.
125
- # This should be overridden by template subclasses.
126
- def allows_script?
127
- true
129
+ # An empty Hash that the template engine can populate with various
130
+ # metadata.
131
+ def metadata
132
+ if respond_to?(:allows_script?)
133
+ self.class.metadata.merge(:allows_script => allows_script?)
134
+ else
135
+ self.class.metadata
136
+ end
128
137
  end
129
138
 
130
- protected
131
- # Called once and only once for each template subclass the first time
132
- # the template class is initialized. This should be used to require the
133
- # underlying template library and perform any initial setup.
134
- def initialize_engine
135
- end
139
+ protected
136
140
 
137
- # Like Kernel#require but issues a warning urging a manual require when
138
- # running under a threaded environment.
139
- def require_template_library(name)
140
- if Thread.list.size > 1
141
- warn "WARN: tilt autoloading '#{name}' in a non thread-safe way; " +
142
- "explicit require '#{name}' suggested."
143
- end
144
- require name
141
+ # @!group For template implementations
142
+
143
+ # The encoding of the source data. Defaults to the
144
+ # default_encoding-option if present. You may override this method
145
+ # in your template class if you have a better hint of the data's
146
+ # encoding.
147
+ def default_encoding
148
+ @default_encoding
145
149
  end
146
150
 
147
151
  # Do whatever preparation is necessary to setup the underlying template
@@ -150,15 +154,11 @@ module Tilt
150
154
  #
151
155
  # Subclasses must provide an implementation of this method.
152
156
  def prepare
153
- if respond_to?(:compile!)
154
- # backward compat with tilt < 0.6; just in case
155
- warn 'Tilt::Template#compile! is deprecated; implement #prepare instead.'
156
- compile!
157
- else
158
- raise NotImplementedError
159
- end
157
+ raise NotImplementedError
160
158
  end
161
159
 
160
+ CLASS_METHOD = Kernel.instance_method(:class)
161
+
162
162
  # Execute the compiled template and return the result string. Template
163
163
  # evaluation is guaranteed to be performed in the scope object with the
164
164
  # locals specified and with support for yielding to the block.
@@ -166,7 +166,18 @@ module Tilt
166
166
  # This method is only used by source generating templates. Subclasses that
167
167
  # override render() may not support all features.
168
168
  def evaluate(scope, locals, &block)
169
- method = compiled_method(locals.keys)
169
+ locals_keys = locals.keys
170
+ locals_keys.sort!{|x, y| x.to_s <=> y.to_s}
171
+ case scope
172
+ when Object
173
+ method = compiled_method(locals_keys, Module === scope ? scope : scope.class)
174
+ else
175
+ if RUBY_VERSION >= '2'
176
+ method = compiled_method(locals_keys, CLASS_METHOD.bind(scope).call)
177
+ else
178
+ method = compiled_method(locals_keys, Object)
179
+ end
180
+ end
170
181
  method.bind(scope).call(locals, &block)
171
182
  end
172
183
 
@@ -179,11 +190,11 @@ module Tilt
179
190
  # control over source generation or want to adjust the default line
180
191
  # offset. In most cases, overriding the #precompiled_template method is
181
192
  # easier and more appropriate.
182
- def precompiled(locals)
183
- preamble = precompiled_preamble(locals)
184
- template = precompiled_template(locals)
185
- postamble = precompiled_postamble(locals)
186
- source = ''
193
+ def precompiled(local_keys)
194
+ preamble = precompiled_preamble(local_keys)
195
+ template = precompiled_template(local_keys)
196
+ postamble = precompiled_postamble(local_keys)
197
+ source = String.new
187
198
 
188
199
  # Ensure that our generated source code has the same encoding as the
189
200
  # the source code generated by the template engine.
@@ -194,10 +205,7 @@ module Tilt
194
205
  template.force_encoding(template_encoding)
195
206
  end
196
207
 
197
- # https://github.com/rtomayko/tilt/issues/193
198
- warn "precompiled_preamble should return String (not Array)" if preamble.is_a?(Array)
199
- warn "precompiled_postamble should return String (not Array)" if postamble.is_a?(Array)
200
- source << [preamble, template, postamble].join("\n")
208
+ source << preamble << "\n" << template << "\n" << postamble
201
209
 
202
210
  [source, preamble.count("\n")+1]
203
211
  end
@@ -208,17 +216,40 @@ module Tilt
208
216
  # the base Template guarantees correct file/line handling, locals
209
217
  # support, custom scopes, proper encoding, and support for template
210
218
  # compilation.
211
- def precompiled_template(locals)
219
+ def precompiled_template(local_keys)
212
220
  raise NotImplementedError
213
221
  end
214
222
 
215
- # Generates preamble code for initializing template state, and performing
216
- # locals assignment. The default implementation performs locals
217
- # assignment only. Lines included in the preamble are subtracted from the
218
- # source line offset, so adding code to the preamble does not effect line
219
- # reporting in Kernel::caller and backtraces.
220
- def precompiled_preamble(locals)
221
- locals.map do |k,v|
223
+ def precompiled_preamble(local_keys)
224
+ ''
225
+ end
226
+
227
+ def precompiled_postamble(local_keys)
228
+ ''
229
+ end
230
+
231
+ # !@endgroup
232
+
233
+ private
234
+
235
+ def read_template_file
236
+ data = File.open(file, 'rb') { |io| io.read }
237
+ if data.respond_to?(:force_encoding)
238
+ # Set it to the default external (without verifying)
239
+ data.force_encoding(Encoding.default_external) if Encoding.default_external
240
+ end
241
+ data
242
+ end
243
+
244
+ # The compiled method for the locals keys provided.
245
+ def compiled_method(locals_keys, scope_class=nil)
246
+ LOCK.synchronize do
247
+ @compiled_method[[scope_class, locals_keys]] ||= compile_template_method(locals_keys, scope_class)
248
+ end
249
+ end
250
+
251
+ def local_extraction(local_keys)
252
+ local_keys.map do |k|
222
253
  if k.to_s =~ /\A[a-z_][a-zA-Z_0-9]*\z/
223
254
  "#{k} = locals[#{k.inspect}]"
224
255
  else
@@ -227,41 +258,26 @@ module Tilt
227
258
  end.join("\n")
228
259
  end
229
260
 
230
- # Generates postamble code for the precompiled template source. The
231
- # string returned from this method is appended to the precompiled
232
- # template source.
233
- def precompiled_postamble(locals)
234
- ''
235
- end
236
-
237
- # The compiled method for the locals keys provided.
238
- def compiled_method(locals_keys)
239
- @compiled_method[locals_keys] ||=
240
- compile_template_method(locals_keys)
241
- end
261
+ def compile_template_method(local_keys, scope_class=nil)
262
+ source, offset = precompiled(local_keys)
263
+ local_code = local_extraction(local_keys)
242
264
 
243
- private
244
- def compile_template_method(locals)
245
- source, offset = precompiled(locals)
246
265
  method_name = "__tilt_#{Thread.current.object_id.abs}"
247
- method_source = ""
266
+ method_source = String.new
248
267
 
249
268
  if method_source.respond_to?(:force_encoding)
250
- method_source.force_encoding(source.encoding)
269
+ method_source.force_encoding(source.encoding)
251
270
  end
252
271
 
253
272
  method_source << <<-RUBY
254
273
  TOPOBJECT.class_eval do
255
274
  def #{method_name}(locals)
256
- Thread.current[:tilt_vars] = [self, locals]
257
- class << self
258
- this, locals = Thread.current[:tilt_vars]
259
- this.instance_eval do
275
+ #{local_code}
260
276
  RUBY
261
277
  offset += method_source.count("\n")
262
278
  method_source << source
263
- method_source << "\nend;end;end;end"
264
- Object.class_eval method_source, eval_file, line - offset
279
+ method_source << "\nend;end;"
280
+ (scope_class || Object).class_eval(method_source, eval_file, line - offset)
265
281
  unbind_compiled_method(method_name)
266
282
  end
267
283
 
@@ -276,7 +292,7 @@ module Tilt
276
292
  end
277
293
 
278
294
  def extract_magic_comment(script)
279
- binary script do
295
+ binary(script) do
280
296
  script[/\A[ \t]*\#.*coding\s*[=:]\s*([[:alnum:]\-_]+).*$/n, 1]
281
297
  end
282
298
  end
@@ -0,0 +1,26 @@
1
+ require 'tilt/template'
2
+ require 'typescript-node'
3
+
4
+ module Tilt
5
+ class TypeScriptTemplate < Template
6
+ self.default_mime_type = 'application/javascript'
7
+
8
+ def prepare
9
+ @option_args = []
10
+
11
+ options.each do |key, value|
12
+ next unless value
13
+
14
+ @option_args << "--#{key}"
15
+
16
+ if value != true
17
+ @option_args << value.to_s
18
+ end
19
+ end
20
+ end
21
+
22
+ def evaluate(scope, locals, &block)
23
+ @output ||= TypeScript::Node.compile(data, *@option_args)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ require 'tilt/template'
2
+ require 'wikicloth'
3
+
4
+ module Tilt
5
+ # WikiCloth implementation. See:
6
+ # http://redcloth.org/
7
+ class WikiClothTemplate < Template
8
+ def prepare
9
+ @parser = options.delete(:parser) || WikiCloth::Parser
10
+ @engine = @parser.new options.merge(:data => data)
11
+ @output = nil
12
+ end
13
+
14
+ def evaluate(scope, locals, &block)
15
+ @output ||= @engine.to_html
16
+ end
17
+
18
+ def allows_script?
19
+ false
20
+ end
21
+ end
22
+ end
data/lib/tilt/yajl.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'tilt/template'
2
+ require 'yajl'
2
3
 
3
4
  module Tilt
4
5
 
@@ -42,14 +43,6 @@ module Tilt
42
43
 
43
44
  self.default_mime_type = 'application/json'
44
45
 
45
- def self.engine_initialized?
46
- defined? ::Yajl
47
- end
48
-
49
- def initialize_engine
50
- require_template_library 'yajl'
51
- end
52
-
53
46
  def prepare
54
47
  end
55
48