tilt 1.3.7 → 1.4.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/CHANGELOG.md +4 -0
- data/README.md +21 -0
- data/lib/tilt.rb +1 -1
- data/lib/tilt/template.rb +67 -24
- data/test/tilt_markdown_test.rb +1 -1
- data/test/tilt_template_test.rb +97 -0
- data/tilt.gemspec +2 -2
- metadata +2 -2
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -194,6 +194,27 @@ template, but if you depend on a specific implementation, you should use #prefer
|
|
194
194
|
When a file extension has a preferred template class, Tilt will *always* use
|
195
195
|
that class, even if it raises an exception.
|
196
196
|
|
197
|
+
Encodings
|
198
|
+
---------
|
199
|
+
|
200
|
+
Tilt needs to know the encoding of the template in order to work properly:
|
201
|
+
|
202
|
+
Tilt will use `Encoding.default_external` as the encoding when reading external
|
203
|
+
files. If you're mostly working with one encoding (e.g. UTF-8) we *highly*
|
204
|
+
recommend setting this option. When providing a custom reader block (`Tilt.new
|
205
|
+
{ custom_string }`) you'll have ensure the string is properly encoded yourself.
|
206
|
+
|
207
|
+
Most of the template engines in Tilt also allows you to override the encoding
|
208
|
+
using the `:default_encoding`-option:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
tmpl = Tilt.new('hello.erb', :default_encoding => 'Big5')
|
212
|
+
```
|
213
|
+
|
214
|
+
Ultimately it's up to the template engine how to handle the encoding: It might
|
215
|
+
respect `:default_encoding`, it might always assume it's UTF-8 (like
|
216
|
+
CoffeScript), or it can do its own encoding detection.
|
217
|
+
|
197
218
|
Template Compilation
|
198
219
|
--------------------
|
199
220
|
|
data/lib/tilt.rb
CHANGED
data/lib/tilt/template.rb
CHANGED
@@ -65,11 +65,37 @@ module Tilt
|
|
65
65
|
@default_encoding = @options.delete :default_encoding
|
66
66
|
|
67
67
|
# load template data and prepare (uses binread to avoid encoding issues)
|
68
|
-
@reader = block || lambda { |t|
|
68
|
+
@reader = block || lambda { |t| read_template_file }
|
69
69
|
@data = @reader.call(self)
|
70
|
+
|
71
|
+
if @data.respond_to?(:force_encoding)
|
72
|
+
@data.force_encoding(default_encoding) if default_encoding
|
73
|
+
|
74
|
+
if !@data.valid_encoding?
|
75
|
+
raise Encoding::InvalidByteSequenceError, "#{eval_file} is not valid #{@data.encoding}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
70
79
|
prepare
|
71
80
|
end
|
72
81
|
|
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
|
+
|
73
99
|
# Render the template in the given scope with the locals specified. If a
|
74
100
|
# block is given, it is typically available within the template via
|
75
101
|
# +yield+.
|
@@ -156,26 +182,29 @@ module Tilt
|
|
156
182
|
def precompiled(locals)
|
157
183
|
preamble = precompiled_preamble(locals)
|
158
184
|
template = precompiled_template(locals)
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
185
|
+
postamble = precompiled_postamble(locals)
|
186
|
+
source = ''
|
187
|
+
|
188
|
+
# Ensure that our generated source code has the same encoding as the
|
189
|
+
# the source code generated by the template engine.
|
190
|
+
if source.respond_to?(:force_encoding)
|
191
|
+
template_encoding = extract_encoding(template)
|
192
|
+
|
193
|
+
source.force_encoding(template_encoding)
|
194
|
+
template.force_encoding(template_encoding)
|
164
195
|
end
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
]
|
170
|
-
[parts.join("\n"), preamble.count("\n") + 1]
|
196
|
+
|
197
|
+
source << preamble << "\n" << template << "\n" << postamble
|
198
|
+
|
199
|
+
[source, preamble.count("\n")+1]
|
171
200
|
end
|
172
201
|
|
173
202
|
# A string containing the (Ruby) source code for the template. The
|
174
|
-
# default Template#evaluate implementation requires either this
|
175
|
-
# or the #precompiled method be overridden. When defined,
|
176
|
-
# Template guarantees correct file/line handling, locals
|
177
|
-
# scopes, and support for template
|
178
|
-
#
|
203
|
+
# default Template#evaluate implementation requires either this
|
204
|
+
# method or the #precompiled method be overridden. When defined,
|
205
|
+
# the base Template guarantees correct file/line handling, locals
|
206
|
+
# support, custom scopes, proper encoding, and support for template
|
207
|
+
# compilation.
|
179
208
|
def precompiled_template(locals)
|
180
209
|
raise NotImplementedError
|
181
210
|
end
|
@@ -212,8 +241,13 @@ module Tilt
|
|
212
241
|
def compile_template_method(locals)
|
213
242
|
source, offset = precompiled(locals)
|
214
243
|
method_name = "__tilt_#{Thread.current.object_id.abs}"
|
215
|
-
method_source =
|
216
|
-
|
244
|
+
method_source = ""
|
245
|
+
|
246
|
+
if method_source.respond_to?(:force_encoding)
|
247
|
+
method_source.force_encoding(source.encoding)
|
248
|
+
end
|
249
|
+
|
250
|
+
method_source << <<-RUBY
|
217
251
|
TOPOBJECT.class_eval do
|
218
252
|
def #{method_name}(locals)
|
219
253
|
Thread.current[:tilt_vars] = [self, locals]
|
@@ -234,13 +268,22 @@ module Tilt
|
|
234
268
|
method
|
235
269
|
end
|
236
270
|
|
271
|
+
def extract_encoding(script)
|
272
|
+
extract_magic_comment(script) || script.encoding
|
273
|
+
end
|
274
|
+
|
237
275
|
def extract_magic_comment(script)
|
238
|
-
|
239
|
-
|
240
|
-
comment
|
241
|
-
elsif @default_encoding
|
242
|
-
"# coding: #{@default_encoding}"
|
276
|
+
binary script do
|
277
|
+
script[/\A[ \t]*\#.*coding\s*[=:]\s*([[:alnum:]\-_]+).*$/n, 1]
|
243
278
|
end
|
244
279
|
end
|
280
|
+
|
281
|
+
def binary(string)
|
282
|
+
original_encoding = string.encoding
|
283
|
+
string.force_encoding(Encoding::BINARY)
|
284
|
+
yield
|
285
|
+
ensure
|
286
|
+
string.force_encoding(original_encoding)
|
287
|
+
end
|
245
288
|
end
|
246
289
|
end
|
data/test/tilt_markdown_test.rb
CHANGED
data/test/tilt_template_test.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
require 'contest'
|
2
3
|
require 'tilt'
|
3
4
|
require 'tempfile'
|
@@ -176,4 +177,100 @@ class TiltTemplateTest < Test::Unit::TestCase
|
|
176
177
|
inst = SourceGeneratingMockTemplate.new { |t| 'Hey #{CONSTANT}!' }
|
177
178
|
assert_equal "Hey Bob!", inst.render(Person.new("Joe"))
|
178
179
|
end
|
180
|
+
|
181
|
+
##
|
182
|
+
# Encodings
|
183
|
+
|
184
|
+
class DynamicMockTemplate < MockTemplate
|
185
|
+
def precompiled_template(locals)
|
186
|
+
options[:code]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class UTF8Template < MockTemplate
|
191
|
+
def default_encoding
|
192
|
+
Encoding::UTF_8
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
if ''.respond_to?(:encoding)
|
197
|
+
original_encoding = Encoding.default_external
|
198
|
+
|
199
|
+
setup do
|
200
|
+
@file = Tempfile.open('template')
|
201
|
+
@file.puts "stuff"
|
202
|
+
@file.close
|
203
|
+
@template = @file.path
|
204
|
+
end
|
205
|
+
|
206
|
+
teardown do
|
207
|
+
Encoding.default_external = original_encoding
|
208
|
+
Encoding.default_internal = nil
|
209
|
+
@file.delete
|
210
|
+
end
|
211
|
+
|
212
|
+
test "reading from file assumes default external encoding" do
|
213
|
+
Encoding.default_external = 'Big5'
|
214
|
+
inst = MockTemplate.new(@template)
|
215
|
+
assert_equal 'Big5', inst.data.encoding.to_s
|
216
|
+
end
|
217
|
+
|
218
|
+
test "reading from file with a :default_encoding overrides default external" do
|
219
|
+
Encoding.default_external = 'Big5'
|
220
|
+
inst = MockTemplate.new(@template, :default_encoding => 'GBK')
|
221
|
+
assert_equal 'GBK', inst.data.encoding.to_s
|
222
|
+
end
|
223
|
+
|
224
|
+
test "reading from file with default_internal set does no transcoding" do
|
225
|
+
Encoding.default_internal = 'utf-8'
|
226
|
+
Encoding.default_external = 'Big5'
|
227
|
+
inst = MockTemplate.new(@template)
|
228
|
+
assert_equal 'Big5', inst.data.encoding.to_s
|
229
|
+
end
|
230
|
+
|
231
|
+
test "using provided template data verbatim when given as string" do
|
232
|
+
Encoding.default_internal = 'Big5'
|
233
|
+
inst = MockTemplate.new(@template) { "blah".force_encoding('GBK') }
|
234
|
+
assert_equal 'GBK', inst.data.encoding.to_s
|
235
|
+
end
|
236
|
+
|
237
|
+
test "uses the template from the generated source code" do
|
238
|
+
tmpl = "ふが"
|
239
|
+
code = tmpl.inspect.encode('Shift_JIS')
|
240
|
+
inst = DynamicMockTemplate.new(:code => code) { '' }
|
241
|
+
res = inst.render
|
242
|
+
assert_equal 'Shift_JIS', res.encoding.to_s
|
243
|
+
assert_equal tmpl, res.encode(tmpl.encoding)
|
244
|
+
end
|
245
|
+
|
246
|
+
test "uses the magic comment from the generated source code" do
|
247
|
+
tmpl = "ふが"
|
248
|
+
code = ("# coding: Shift_JIS\n" + tmpl.inspect).encode('Shift_JIS')
|
249
|
+
# Set it to an incorrect encoding
|
250
|
+
code.force_encoding('UTF-8')
|
251
|
+
|
252
|
+
inst = DynamicMockTemplate.new(:code => code) { '' }
|
253
|
+
res = inst.render
|
254
|
+
assert_equal 'Shift_JIS', res.encoding.to_s
|
255
|
+
assert_equal tmpl, res.encode(tmpl.encoding)
|
256
|
+
end
|
257
|
+
|
258
|
+
test "uses #default_encoding instead of default_external" do
|
259
|
+
Encoding.default_external = 'Big5'
|
260
|
+
inst = UTF8Template.new(@template)
|
261
|
+
assert_equal 'UTF-8', inst.data.encoding.to_s
|
262
|
+
end
|
263
|
+
|
264
|
+
test "uses #default_encoding instead of current encoding" do
|
265
|
+
tmpl = "".force_encoding('Big5')
|
266
|
+
inst = UTF8Template.new(@template) { tmpl }
|
267
|
+
assert_equal 'UTF-8', inst.data.encoding.to_s
|
268
|
+
end
|
269
|
+
|
270
|
+
test "raises error if the encoding is not valid" do
|
271
|
+
assert_raises(Encoding::InvalidByteSequenceError) do
|
272
|
+
UTF8Template.new(@template) { "\xe4" }
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
179
276
|
end
|
data/tilt.gemspec
CHANGED
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'tilt'
|
6
|
-
s.version = '1.
|
7
|
-
s.date = '2013-
|
6
|
+
s.version = '1.4.0'
|
7
|
+
s.date = '2013-05-01'
|
8
8
|
|
9
9
|
s.description = "Generic interface to multiple Ruby template engines"
|
10
10
|
s.summary = s.description
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tilt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: asciidoctor
|