tilt 1.2.2 → 1.3
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/README.md +54 -24
- data/TEMPLATES.md +250 -175
- data/lib/tilt.rb +104 -817
- data/lib/tilt/builder.rb +40 -0
- data/lib/tilt/coffee.rb +50 -0
- data/lib/tilt/creole.rb +28 -0
- data/lib/tilt/css.rb +67 -0
- data/lib/tilt/erb.rb +110 -0
- data/lib/tilt/haml.rb +64 -0
- data/lib/tilt/liquid.rb +41 -0
- data/lib/tilt/markaby.rb +52 -0
- data/lib/tilt/markdown.rb +131 -0
- data/lib/tilt/nokogiri.rb +43 -0
- data/lib/tilt/radius.rb +51 -0
- data/lib/tilt/rdoc.rb +32 -0
- data/lib/tilt/string.rb +21 -0
- data/lib/tilt/template.rb +285 -0
- data/lib/tilt/textile.rb +25 -0
- data/test/tilt_blueclothtemplate_test.rb +6 -25
- data/test/tilt_coffeescripttemplate_test.rb +31 -1
- data/test/tilt_creoletemplate_test.rb +24 -0
- data/test/tilt_erbtemplate_test.rb +18 -19
- data/test/tilt_erubistemplate_test.rb +12 -2
- data/test/tilt_fallback_test.rb +122 -0
- data/test/tilt_hamltemplate_test.rb +4 -4
- data/test/tilt_kramdown_test.rb +42 -0
- data/test/tilt_markdown_test.rb +149 -0
- data/test/tilt_marukutemplate_test.rb +48 -0
- data/test/tilt_rdiscounttemplate_test.rb +16 -6
- data/test/tilt_redcarpettemplate_test.rb +55 -0
- data/test/tilt_stringtemplate_test.rb +10 -3
- data/test/tilt_template_test.rb +6 -0
- data/tilt.gemspec +28 -2
- metadata +86 -36
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
|
3
|
+
module Tilt
|
4
|
+
# Discount Markdown implementation. See:
|
5
|
+
# http://github.com/rtomayko/rdiscount
|
6
|
+
#
|
7
|
+
# RDiscount is a simple text filter. It does not support +scope+ or
|
8
|
+
# +locals+. The +:smart+ and +:filter_html+ options may be set true
|
9
|
+
# to enable those flags on the underlying RDiscount object.
|
10
|
+
class RDiscountTemplate < Template
|
11
|
+
self.default_mime_type = 'text/html'
|
12
|
+
|
13
|
+
ALIAS = {
|
14
|
+
:escape_html => :filter_html,
|
15
|
+
:smartypants => :smart
|
16
|
+
}
|
17
|
+
|
18
|
+
FLAGS = [:smart, :filter_html, :smartypants, :escape_html]
|
19
|
+
|
20
|
+
def flags
|
21
|
+
FLAGS.select { |flag| options[flag] }.map { |flag| ALIAS[flag] || flag }
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.engine_initialized?
|
25
|
+
defined? ::RDiscount
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize_engine
|
29
|
+
require_template_library 'rdiscount'
|
30
|
+
end
|
31
|
+
|
32
|
+
def prepare
|
33
|
+
@engine = RDiscount.new(data, *flags)
|
34
|
+
@output = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def evaluate(scope, locals, &block)
|
38
|
+
@output ||= @engine.to_html
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Upskirt Markdown implementation. See:
|
43
|
+
# https://github.com/tanoku/redcarpet
|
44
|
+
#
|
45
|
+
# Compatible to RDiscount
|
46
|
+
class RedcarpetTemplate < RDiscountTemplate
|
47
|
+
self.default_mime_type = 'text/html'
|
48
|
+
|
49
|
+
def self.engine_initialized?
|
50
|
+
defined? ::RedcarpetCompat
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize_engine
|
54
|
+
require_template_library 'redcarpet'
|
55
|
+
end
|
56
|
+
|
57
|
+
def prepare
|
58
|
+
@engine = RedcarpetCompat.new(data, *flags)
|
59
|
+
@output = nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# BlueCloth Markdown implementation. See:
|
64
|
+
# http://deveiate.org/projects/BlueCloth/
|
65
|
+
class BlueClothTemplate < Template
|
66
|
+
self.default_mime_type = 'text/html'
|
67
|
+
|
68
|
+
def self.engine_initialized?
|
69
|
+
defined? ::BlueCloth
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize_engine
|
73
|
+
require_template_library 'bluecloth'
|
74
|
+
end
|
75
|
+
|
76
|
+
def prepare
|
77
|
+
@engine = BlueCloth.new(data, options)
|
78
|
+
@output = nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def evaluate(scope, locals, &block)
|
82
|
+
@output ||= @engine.to_html
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Maruku markdown implementation. See:
|
87
|
+
# http://maruku.rubyforge.org/
|
88
|
+
class MarukuTemplate < Template
|
89
|
+
def self.engine_initialized?
|
90
|
+
defined? ::Maruku
|
91
|
+
end
|
92
|
+
|
93
|
+
def initialize_engine
|
94
|
+
require_template_library 'maruku'
|
95
|
+
end
|
96
|
+
|
97
|
+
def prepare
|
98
|
+
@engine = Maruku.new(data, options)
|
99
|
+
@output = nil
|
100
|
+
end
|
101
|
+
|
102
|
+
def evaluate(scope, locals, &block)
|
103
|
+
@output ||= @engine.to_html
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Kramdown Markdown implementation. See:
|
108
|
+
# http://kramdown.rubyforge.org/
|
109
|
+
class KramdownTemplate < Template
|
110
|
+
DUMB_QUOTES = [39, 39, 34, 34]
|
111
|
+
|
112
|
+
def self.engine_initialized?
|
113
|
+
defined? ::Kramdown
|
114
|
+
end
|
115
|
+
|
116
|
+
def initialize_engine
|
117
|
+
require_template_library 'kramdown'
|
118
|
+
end
|
119
|
+
|
120
|
+
def prepare
|
121
|
+
options[:smart_quotes] = DUMB_QUOTES unless options[:smartypants]
|
122
|
+
@engine = Kramdown::Document.new(data, options)
|
123
|
+
@output = nil
|
124
|
+
end
|
125
|
+
|
126
|
+
def evaluate(scope, locals, &block)
|
127
|
+
@output ||= @engine.to_html
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
|
3
|
+
module Tilt
|
4
|
+
# Nokogiri template implementation. See:
|
5
|
+
# http://nokogiri.org/
|
6
|
+
class NokogiriTemplate < Template
|
7
|
+
self.default_mime_type = 'text/xml'
|
8
|
+
|
9
|
+
def self.engine_initialized?
|
10
|
+
defined? ::Nokogiri
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize_engine
|
14
|
+
require_template_library 'nokogiri'
|
15
|
+
end
|
16
|
+
|
17
|
+
def prepare; end
|
18
|
+
|
19
|
+
def evaluate(scope, locals, &block)
|
20
|
+
block &&= proc { yield.gsub(/^<\?xml version=\"1\.0\"\?>\n?/, "") }
|
21
|
+
|
22
|
+
if data.respond_to?(:to_str)
|
23
|
+
super(scope, locals, &block)
|
24
|
+
else
|
25
|
+
::Nokogiri::XML::Builder.new.tap(&data).to_xml
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def precompiled_preamble(locals)
|
30
|
+
return super if locals.include? :xml
|
31
|
+
"xml = ::Nokogiri::XML::Builder.new\n#{super}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def precompiled_postamble(locals)
|
35
|
+
"xml.to_xml"
|
36
|
+
end
|
37
|
+
|
38
|
+
def precompiled_template(locals)
|
39
|
+
data.to_str
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
data/lib/tilt/radius.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
|
3
|
+
module Tilt
|
4
|
+
# Radius Template
|
5
|
+
# http://github.com/jlong/radius/
|
6
|
+
class RadiusTemplate < Template
|
7
|
+
def self.engine_initialized?
|
8
|
+
defined? ::Radius
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.context_class
|
12
|
+
@context_class ||= Class.new(Radius::Context) do
|
13
|
+
attr_accessor :tilt_scope
|
14
|
+
|
15
|
+
def tag_missing(name, attributes)
|
16
|
+
tilt_scope.__send__(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def dup
|
20
|
+
i = super
|
21
|
+
i.tilt_scope = tilt_scope
|
22
|
+
i
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize_engine
|
28
|
+
require_template_library 'radius'
|
29
|
+
end
|
30
|
+
|
31
|
+
def prepare
|
32
|
+
end
|
33
|
+
|
34
|
+
def evaluate(scope, locals, &block)
|
35
|
+
context = self.class.context_class.new
|
36
|
+
context.tilt_scope = scope
|
37
|
+
context.define_tag("yield") do
|
38
|
+
block.call
|
39
|
+
end
|
40
|
+
locals.each do |tag, value|
|
41
|
+
context.define_tag(tag) do
|
42
|
+
value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
options = {:tag_prefix => 'r'}.merge(@options)
|
47
|
+
parser = Radius::Parser.new(context, options)
|
48
|
+
parser.parse(data)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/tilt/rdoc.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
|
3
|
+
module Tilt
|
4
|
+
# RDoc template. See:
|
5
|
+
# http://rdoc.rubyforge.org/
|
6
|
+
#
|
7
|
+
# It's suggested that your program require 'rdoc/markup' and
|
8
|
+
# 'rdoc/markup/to_html' at load time when using this template
|
9
|
+
# engine.
|
10
|
+
class RDocTemplate < Template
|
11
|
+
self.default_mime_type = 'text/html'
|
12
|
+
|
13
|
+
def self.engine_initialized?
|
14
|
+
defined? ::RDoc::Markup
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize_engine
|
18
|
+
require_template_library 'rdoc/markup'
|
19
|
+
require_template_library 'rdoc/markup/to_html'
|
20
|
+
end
|
21
|
+
|
22
|
+
def prepare
|
23
|
+
markup = RDoc::Markup::ToHtml.new
|
24
|
+
@engine = markup.convert(data)
|
25
|
+
@output = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def evaluate(scope, locals, &block)
|
29
|
+
@output ||= @engine.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/tilt/string.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
|
3
|
+
module Tilt
|
4
|
+
# The template source is evaluated as a Ruby string. The #{} interpolation
|
5
|
+
# syntax can be used to generated dynamic output.
|
6
|
+
class StringTemplate < Template
|
7
|
+
def prepare
|
8
|
+
hash = "TILT#{data.hash.abs}"
|
9
|
+
@code = "<<#{hash}.chomp\n#{data}\n#{hash}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def precompiled_template(locals)
|
13
|
+
@code
|
14
|
+
end
|
15
|
+
|
16
|
+
def precompiled(locals)
|
17
|
+
source, offset = super
|
18
|
+
[source, offset + 1]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
module Tilt
|
2
|
+
TOPOBJECT = defined?(BasicObject) ? BasicObject : Object
|
3
|
+
|
4
|
+
# Base class for template implementations. Subclasses must implement
|
5
|
+
# the #prepare method and one of the #evaluate or #precompiled_template
|
6
|
+
# methods.
|
7
|
+
class Template
|
8
|
+
# Template source; loaded from a file or given directly.
|
9
|
+
attr_reader :data
|
10
|
+
|
11
|
+
# The name of the file where the template data was loaded from.
|
12
|
+
attr_reader :file
|
13
|
+
|
14
|
+
# The line number in #file where template data was loaded from.
|
15
|
+
attr_reader :line
|
16
|
+
|
17
|
+
# A Hash of template engine specific options. This is passed directly
|
18
|
+
# to the underlying engine and is not used by the generic template
|
19
|
+
# interface.
|
20
|
+
attr_reader :options
|
21
|
+
|
22
|
+
# Used to determine if this class's initialize_engine method has
|
23
|
+
# been called yet.
|
24
|
+
@engine_initialized = false
|
25
|
+
class << self
|
26
|
+
attr_accessor :engine_initialized
|
27
|
+
alias engine_initialized? engine_initialized
|
28
|
+
|
29
|
+
attr_accessor :default_mime_type
|
30
|
+
end
|
31
|
+
|
32
|
+
# Create a new template with the file, line, and options specified. By
|
33
|
+
# default, template data is read from the file. When a block is given,
|
34
|
+
# it should read template data and return as a String. When file is nil,
|
35
|
+
# a block is required.
|
36
|
+
#
|
37
|
+
# All arguments are optional.
|
38
|
+
def initialize(file=nil, line=1, options={}, &block)
|
39
|
+
@file, @line, @options = nil, 1, {}
|
40
|
+
|
41
|
+
[options, line, file].compact.each do |arg|
|
42
|
+
case
|
43
|
+
when arg.respond_to?(:to_str) ; @file = arg.to_str
|
44
|
+
when arg.respond_to?(:to_int) ; @line = arg.to_int
|
45
|
+
when arg.respond_to?(:to_hash) ; @options = arg.to_hash.dup
|
46
|
+
else raise TypeError
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
raise ArgumentError, "file or block required" if (@file || block).nil?
|
51
|
+
|
52
|
+
# call the initialize_engine method if this is the very first time
|
53
|
+
# an instance of this class has been created.
|
54
|
+
if !self.class.engine_initialized?
|
55
|
+
initialize_engine
|
56
|
+
self.class.engine_initialized = true
|
57
|
+
end
|
58
|
+
|
59
|
+
# used to hold compiled template methods
|
60
|
+
@compiled_method = {}
|
61
|
+
|
62
|
+
# used on 1.9 to set the encoding if it is not set elsewhere (like a magic comment)
|
63
|
+
# currently only used if template compiles to ruby
|
64
|
+
@default_encoding = @options.delete :default_encoding
|
65
|
+
|
66
|
+
# load template data and prepare (uses binread to avoid encoding issues)
|
67
|
+
@reader = block || lambda { |t| File.respond_to?(:binread) ? File.binread(@file) : File.read(@file) }
|
68
|
+
@data = @reader.call(self)
|
69
|
+
prepare
|
70
|
+
end
|
71
|
+
|
72
|
+
# Render the template in the given scope with the locals specified. If a
|
73
|
+
# block is given, it is typically available within the template via
|
74
|
+
# +yield+.
|
75
|
+
def render(scope=Object.new, locals={}, &block)
|
76
|
+
evaluate scope, locals || {}, &block
|
77
|
+
end
|
78
|
+
|
79
|
+
# The basename of the template file.
|
80
|
+
def basename(suffix='')
|
81
|
+
File.basename(file, suffix) if file
|
82
|
+
end
|
83
|
+
|
84
|
+
# The template file's basename with all extensions chomped off.
|
85
|
+
def name
|
86
|
+
basename.split('.', 2).first if basename
|
87
|
+
end
|
88
|
+
|
89
|
+
# The filename used in backtraces to describe the template.
|
90
|
+
def eval_file
|
91
|
+
file || '(__TEMPLATE__)'
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
# Called once and only once for each template subclass the first time
|
96
|
+
# the template class is initialized. This should be used to require the
|
97
|
+
# underlying template library and perform any initial setup.
|
98
|
+
def initialize_engine
|
99
|
+
end
|
100
|
+
|
101
|
+
# Like Kernel::require but issues a warning urging a manual require when
|
102
|
+
# running under a threaded environment.
|
103
|
+
def require_template_library(name)
|
104
|
+
if Thread.list.size > 1
|
105
|
+
warn "WARN: tilt autoloading '#{name}' in a non thread-safe way; " +
|
106
|
+
"explicit require '#{name}' suggested."
|
107
|
+
end
|
108
|
+
require name
|
109
|
+
end
|
110
|
+
|
111
|
+
# Do whatever preparation is necessary to setup the underlying template
|
112
|
+
# engine. Called immediately after template data is loaded. Instance
|
113
|
+
# variables set in this method are available when #evaluate is called.
|
114
|
+
#
|
115
|
+
# Subclasses must provide an implementation of this method.
|
116
|
+
def prepare
|
117
|
+
if respond_to?(:compile!)
|
118
|
+
# backward compat with tilt < 0.6; just in case
|
119
|
+
warn 'Tilt::Template#compile! is deprecated; implement #prepare instead.'
|
120
|
+
compile!
|
121
|
+
else
|
122
|
+
raise NotImplementedError
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def evaluate(scope, locals, &block)
|
127
|
+
cached_evaluate(scope, locals, &block)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Process the template and return the result. The first time this
|
131
|
+
# method is called, the template source is evaluated with instance_eval.
|
132
|
+
# On the sequential method calls it will compile the template to an
|
133
|
+
# unbound method which will lead to better performance. In any case,
|
134
|
+
# template executation is guaranteed to be performed in the scope object
|
135
|
+
# with the locals specified and with support for yielding to the block.
|
136
|
+
def cached_evaluate(scope, locals, &block)
|
137
|
+
# Redefine itself to use method compilation the next time:
|
138
|
+
def self.cached_evaluate(scope, locals, &block)
|
139
|
+
method = compiled_method(locals.keys)
|
140
|
+
method.bind(scope).call(locals, &block)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Use instance_eval the first time:
|
144
|
+
evaluate_source(scope, locals, &block)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Generates all template source by combining the preamble, template, and
|
148
|
+
# postamble and returns a two-tuple of the form: [source, offset], where
|
149
|
+
# source is the string containing (Ruby) source code for the template and
|
150
|
+
# offset is the integer line offset where line reporting should begin.
|
151
|
+
#
|
152
|
+
# Template subclasses may override this method when they need complete
|
153
|
+
# control over source generation or want to adjust the default line
|
154
|
+
# offset. In most cases, overriding the #precompiled_template method is
|
155
|
+
# easier and more appropriate.
|
156
|
+
def precompiled(locals)
|
157
|
+
preamble = precompiled_preamble(locals)
|
158
|
+
template = precompiled_template(locals)
|
159
|
+
magic_comment = extract_magic_comment(template)
|
160
|
+
if magic_comment
|
161
|
+
# Magic comment e.g. "# coding: utf-8" has to be in the first line.
|
162
|
+
# So we copy the magic comment to the first line.
|
163
|
+
preamble = magic_comment + "\n" + preamble
|
164
|
+
end
|
165
|
+
parts = [
|
166
|
+
preamble,
|
167
|
+
template,
|
168
|
+
precompiled_postamble(locals)
|
169
|
+
]
|
170
|
+
[parts.join("\n"), preamble.count("\n") + 1]
|
171
|
+
end
|
172
|
+
|
173
|
+
# A string containing the (Ruby) source code for the template. The
|
174
|
+
# default Template#evaluate implementation requires either this method
|
175
|
+
# or the #precompiled method be overridden. When defined, the base
|
176
|
+
# Template guarantees correct file/line handling, locals support, custom
|
177
|
+
# scopes, and support for template compilation when the scope object
|
178
|
+
# allows it.
|
179
|
+
def precompiled_template(locals)
|
180
|
+
raise NotImplementedError
|
181
|
+
end
|
182
|
+
|
183
|
+
# Generates preamble code for initializing template state, and performing
|
184
|
+
# locals assignment. The default implementation performs locals
|
185
|
+
# assignment only. Lines included in the preamble are subtracted from the
|
186
|
+
# source line offset, so adding code to the preamble does not effect line
|
187
|
+
# reporting in Kernel::caller and backtraces.
|
188
|
+
def precompiled_preamble(locals)
|
189
|
+
locals.map { |k,v| "#{k} = locals[#{k.inspect}]" }.join("\n")
|
190
|
+
end
|
191
|
+
|
192
|
+
# Generates postamble code for the precompiled template source. The
|
193
|
+
# string returned from this method is appended to the precompiled
|
194
|
+
# template source.
|
195
|
+
def precompiled_postamble(locals)
|
196
|
+
''
|
197
|
+
end
|
198
|
+
|
199
|
+
# The compiled method for the locals keys provided.
|
200
|
+
def compiled_method(locals_keys)
|
201
|
+
@compiled_method[locals_keys] ||=
|
202
|
+
compile_template_method(locals_keys)
|
203
|
+
end
|
204
|
+
|
205
|
+
private
|
206
|
+
# Evaluate the template source in the context of the scope object.
|
207
|
+
def evaluate_source(scope, locals, &block)
|
208
|
+
source, offset = precompiled(locals)
|
209
|
+
scope.instance_eval(source, eval_file, line - offset)
|
210
|
+
end
|
211
|
+
|
212
|
+
# JRuby doesn't allow Object#instance_eval to yield to the block it's
|
213
|
+
# closed over. This is by design and (ostensibly) something that will
|
214
|
+
# change in MRI, though no current MRI version tested (1.8.6 - 1.9.2)
|
215
|
+
# exhibits the behavior. More info here:
|
216
|
+
#
|
217
|
+
# http://jira.codehaus.org/browse/JRUBY-2599
|
218
|
+
#
|
219
|
+
# We redefine evaluate_source to work around this issues.
|
220
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
221
|
+
undef evaluate_source
|
222
|
+
def evaluate_source(scope, locals, &block)
|
223
|
+
source, offset = precompiled(locals)
|
224
|
+
file, lineno = eval_file, (line - offset)
|
225
|
+
scope.instance_eval { Kernel::eval(source, binding, file, lineno) }
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def compile_template_method(locals)
|
230
|
+
source, offset = precompiled(locals)
|
231
|
+
offset += 5
|
232
|
+
method_name = "__tilt_#{Thread.current.object_id.abs}"
|
233
|
+
Object.class_eval <<-RUBY, eval_file, line - offset
|
234
|
+
#{extract_magic_comment source}
|
235
|
+
TOPOBJECT.class_eval do
|
236
|
+
def #{method_name}(locals)
|
237
|
+
Thread.current[:tilt_vars] = [self, locals]
|
238
|
+
class << self
|
239
|
+
this, locals = Thread.current[:tilt_vars]
|
240
|
+
this.instance_eval do
|
241
|
+
#{source}
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
RUBY
|
247
|
+
unbind_compiled_method(method_name)
|
248
|
+
end
|
249
|
+
|
250
|
+
def unbind_compiled_method(method_name)
|
251
|
+
method = TOPOBJECT.instance_method(method_name)
|
252
|
+
TOPOBJECT.class_eval { remove_method(method_name) }
|
253
|
+
method
|
254
|
+
end
|
255
|
+
|
256
|
+
def extract_magic_comment(script)
|
257
|
+
comment = script.slice(/\A[ \t]*\#.*coding\s*[=:]\s*([[:alnum:]\-_]+).*$/)
|
258
|
+
return comment if comment and not %w[ascii-8bit binary].include?($1.downcase)
|
259
|
+
"# coding: #{@default_encoding}" if @default_encoding
|
260
|
+
end
|
261
|
+
|
262
|
+
# Special case Ruby 1.9.1's broken yield.
|
263
|
+
#
|
264
|
+
# http://github.com/rtomayko/tilt/commit/20c01a5
|
265
|
+
# http://redmine.ruby-lang.org/issues/show/3601
|
266
|
+
#
|
267
|
+
# Remove when 1.9.2 dominates 1.9.1 installs in the wild.
|
268
|
+
if RUBY_VERSION =~ /^1.9.1/
|
269
|
+
undef compile_template_method
|
270
|
+
def compile_template_method(locals)
|
271
|
+
source, offset = precompiled(locals)
|
272
|
+
offset += 1
|
273
|
+
method_name = "__tilt_#{Thread.current.object_id}"
|
274
|
+
Object.class_eval <<-RUBY, eval_file, line - offset
|
275
|
+
TOPOBJECT.class_eval do
|
276
|
+
def #{method_name}(locals)
|
277
|
+
#{source}
|
278
|
+
end
|
279
|
+
end
|
280
|
+
RUBY
|
281
|
+
unbind_compiled_method(method_name)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|