tilt 0.5 → 0.7
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 +6 -0
- data/Rakefile +33 -32
- data/TEMPLATES.md +15 -4
- data/lib/tilt.rb +225 -94
- data/test/tilt_buildertemplate_test.rb +1 -1
- data/test/tilt_coffeetemplate_test.rb +20 -0
- data/test/tilt_compilesite_test.rb +62 -0
- data/test/tilt_erbtemplate_test.rb +104 -2
- data/test/tilt_erubistemplate_test.rb +9 -1
- data/test/tilt_hamltemplate_test.rb +54 -1
- data/test/tilt_liquidtemplate_test.rb +1 -1
- data/test/tilt_mustache_views/external.rb +9 -0
- data/test/tilt_mustachetemplate_test.rb +9 -3
- data/test/tilt_rdiscounttemplate_test.rb +3 -3
- data/test/tilt_rdoctemplate_test.rb +1 -1
- data/test/tilt_stringtemplate_test.rb +87 -1
- data/test/tilt_template_test.rb +28 -23
- data/tilt.gemspec +6 -2
- metadata +73 -36
data/README.md
CHANGED
|
@@ -33,6 +33,12 @@ Support for these template engines is included with the package:
|
|
|
33
33
|
RDiscount .markdown rdiscount
|
|
34
34
|
RedCloth .textile redcloth
|
|
35
35
|
|
|
36
|
+
See [TEMPLATES.md][t] for detailed information on template engine
|
|
37
|
+
options and supported features.
|
|
38
|
+
|
|
39
|
+
[t]: http://github.com/rtomayko/tilt/blob/master/TEMPLATES.md
|
|
40
|
+
"Tilt Template Engine Documentation"
|
|
41
|
+
|
|
36
42
|
Basic Usage
|
|
37
43
|
-----------
|
|
38
44
|
|
data/Rakefile
CHANGED
|
@@ -16,38 +16,39 @@ end
|
|
|
16
16
|
|
|
17
17
|
# PACKAGING =================================================================
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def package(ext='')
|
|
23
|
-
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
desc 'Build packages'
|
|
27
|
-
task :package => %w[.gem .tar.gz].map {|e| package(e)}
|
|
28
|
-
|
|
29
|
-
desc 'Build and install as local gem'
|
|
30
|
-
task :install => package('.gem') do
|
|
31
|
-
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
directory '
|
|
35
|
-
|
|
36
|
-
file package('.gem') => %w[
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
file package('.tar.gz') => %w[
|
|
42
|
-
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
desc 'Upload gem and tar.gz distributables to rubyforge'
|
|
46
|
-
task :release => [package('.gem'), package('.tar.gz')] do |t|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
19
|
+
if defined?(Gem)
|
|
20
|
+
SPEC = eval(File.read('tilt.gemspec'))
|
|
21
|
+
|
|
22
|
+
def package(ext='')
|
|
23
|
+
"pkg/tilt-#{SPEC.version}" + ext
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
desc 'Build packages'
|
|
27
|
+
task :package => %w[.gem .tar.gz].map {|e| package(e)}
|
|
28
|
+
|
|
29
|
+
desc 'Build and install as local gem'
|
|
30
|
+
task :install => package('.gem') do
|
|
31
|
+
sh "gem install #{package('.gem')}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
directory 'pkg/'
|
|
35
|
+
|
|
36
|
+
file package('.gem') => %w[pkg/ tilt.gemspec] + SPEC.files do |f|
|
|
37
|
+
sh "gem build tilt.gemspec"
|
|
38
|
+
mv File.basename(f.name), f.name
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
file package('.tar.gz') => %w[pkg/] + SPEC.files do |f|
|
|
42
|
+
sh "git archive --format=tar HEAD | gzip > #{f.name}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
desc 'Upload gem and tar.gz distributables to rubyforge'
|
|
46
|
+
task :release => [package('.gem'), package('.tar.gz')] do |t|
|
|
47
|
+
sh <<-SH
|
|
48
|
+
rubyforge add_release sinatra tilt #{SPEC.version} #{package('.gem')} &&
|
|
49
|
+
rubyforge add_file sinatra tilt #{SPEC.version} #{package('.tar.gz')}
|
|
50
|
+
SH
|
|
51
|
+
end
|
|
51
52
|
end
|
|
52
53
|
|
|
53
54
|
# GEMSPEC ===================================================================
|
data/TEMPLATES.md
CHANGED
|
@@ -67,6 +67,12 @@ of any combination of the following characters:
|
|
|
67
67
|
The `$SAFE` level; when set, ERB code will be run in a
|
|
68
68
|
separate thread with `$SAFE` set to the provided level.
|
|
69
69
|
|
|
70
|
+
#### `:outvar => '_erbout'`
|
|
71
|
+
|
|
72
|
+
The name of the variable used to accumulate template output. This can be
|
|
73
|
+
any valid Ruby expression but must be assignable. By default a local
|
|
74
|
+
variable named `_erbout` is used.
|
|
75
|
+
|
|
70
76
|
### See also
|
|
71
77
|
|
|
72
78
|
* [ERB documentation](http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html)
|
|
@@ -98,14 +104,19 @@ Set pattern for embedded Ruby code.
|
|
|
98
104
|
|
|
99
105
|
See the [ERB](#erb) template documentation for examples, usage, and options.
|
|
100
106
|
|
|
101
|
-
|
|
102
|
-
|
|
107
|
+
#### `:outvar => '_erbout'`
|
|
108
|
+
|
|
109
|
+
The name of the variable used to accumulate template output. This can be
|
|
110
|
+
any valid Ruby expression but must be assignable. By default a local
|
|
111
|
+
variable named `_erbout` is used.
|
|
103
112
|
|
|
104
113
|
### See also
|
|
105
114
|
|
|
106
115
|
* [Erubis Home](http://www.kuwata-lab.com/erubis/)
|
|
107
116
|
* [Erubis User's Guide](http://www.kuwata-lab.com/erubis/users-guide.html)
|
|
108
117
|
|
|
118
|
+
__NOTE:__ It's suggested that your program `require 'erubis'` at load time when
|
|
119
|
+
using this template engine within a threaded environment.
|
|
109
120
|
|
|
110
121
|
<a name='haml'></a>
|
|
111
122
|
Haml (`haml`)
|
|
@@ -308,9 +319,9 @@ The class or module where View classes are located. If you have
|
|
|
308
319
|
`Hurl::App::Views`, namespace should be `Hurl:App`. This defaults to `Object`,
|
|
309
320
|
causing `::Views` to be searched for classes.
|
|
310
321
|
|
|
311
|
-
#### `:mustaches => nil`
|
|
322
|
+
#### `:mustaches => nil` or `:view_path => nil`
|
|
312
323
|
|
|
313
|
-
Where mustache views (
|
|
324
|
+
Where mustache views (`.rb` files) are located, or `nil` to disable auto-requiring
|
|
314
325
|
of views based on template names. By default, the view file is assumed to be in
|
|
315
326
|
the same directory as the template file.
|
|
316
327
|
|
data/lib/tilt.rb
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
module Tilt
|
|
2
|
-
VERSION = '0.
|
|
2
|
+
VERSION = '0.7'
|
|
3
3
|
|
|
4
4
|
@template_mappings = {}
|
|
5
5
|
|
|
6
|
-
# Hash of template path pattern => template implementation
|
|
7
|
-
# class mappings.
|
|
6
|
+
# Hash of template path pattern => template implementation class mappings.
|
|
8
7
|
def self.mappings
|
|
9
8
|
@template_mappings
|
|
10
9
|
end
|
|
@@ -25,7 +24,7 @@ module Tilt
|
|
|
25
24
|
end
|
|
26
25
|
end
|
|
27
26
|
|
|
28
|
-
# Lookup a template class
|
|
27
|
+
# Lookup a template class for the given filename or file
|
|
29
28
|
# extension. Return nil when no implementation is found.
|
|
30
29
|
def self.[](file)
|
|
31
30
|
if @template_mappings.key?(pattern = file.to_s.downcase)
|
|
@@ -44,9 +43,24 @@ module Tilt
|
|
|
44
43
|
end
|
|
45
44
|
end
|
|
46
45
|
|
|
46
|
+
# Mixin allowing template compilation on scope objects.
|
|
47
|
+
#
|
|
48
|
+
# Including this module in scope objects passed to Template#render
|
|
49
|
+
# causes template source to be compiled to methods the first time they're
|
|
50
|
+
# used. This can yield significant (5x-10x) performance increases for
|
|
51
|
+
# templates that support it (ERB, Erubis, Builder).
|
|
52
|
+
#
|
|
53
|
+
# It's also possible (though not recommended) to include this module in
|
|
54
|
+
# Object to enable template compilation globally. The downside is that
|
|
55
|
+
# the template methods will polute the global namespace and could lead to
|
|
56
|
+
# unexpected behavior.
|
|
57
|
+
module CompileSite
|
|
58
|
+
def __tilt__
|
|
59
|
+
end
|
|
60
|
+
end
|
|
47
61
|
|
|
48
62
|
# Base class for template implementations. Subclasses must implement
|
|
49
|
-
# the #
|
|
63
|
+
# the #prepare method and one of the #evaluate or #template_source
|
|
50
64
|
# methods.
|
|
51
65
|
class Template
|
|
52
66
|
# Template source; loaded from a file or given directly.
|
|
@@ -63,51 +77,55 @@ module Tilt
|
|
|
63
77
|
# interface.
|
|
64
78
|
attr_reader :options
|
|
65
79
|
|
|
80
|
+
# Used to determine if this class's initialize_engine method has
|
|
81
|
+
# been called yet.
|
|
82
|
+
@engine_initialized = false
|
|
83
|
+
class << self
|
|
84
|
+
attr_accessor :engine_initialized
|
|
85
|
+
alias engine_initialized? engine_initialized
|
|
86
|
+
end
|
|
87
|
+
|
|
66
88
|
# Create a new template with the file, line, and options specified. By
|
|
67
|
-
# default, template data is read from the file
|
|
68
|
-
#
|
|
69
|
-
#
|
|
89
|
+
# default, template data is read from the file. When a block is given,
|
|
90
|
+
# it should read template data and return as a String. When file is nil,
|
|
91
|
+
# a block is required.
|
|
70
92
|
#
|
|
71
|
-
#
|
|
72
|
-
# time this template subclass has been initialized.
|
|
93
|
+
# All arguments are optional.
|
|
73
94
|
def initialize(file=nil, line=1, options={}, &block)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
95
|
+
@file, @line, @options = nil, 1, {}
|
|
96
|
+
|
|
97
|
+
[options, line, file].compact.each do |arg|
|
|
98
|
+
case
|
|
99
|
+
when arg.respond_to?(:to_str) ; @file = arg.to_str
|
|
100
|
+
when arg.respond_to?(:to_int) ; @line = arg.to_int
|
|
101
|
+
when arg.respond_to?(:to_hash) ; @options = arg.to_hash
|
|
102
|
+
else raise TypeError
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
raise ArgumentError, "file or block required" if (@file || block).nil?
|
|
107
|
+
|
|
108
|
+
# call the initialize_engine method if this is the very first time
|
|
109
|
+
# an instance of this class has been created.
|
|
110
|
+
if !self.class.engine_initialized?
|
|
82
111
|
initialize_engine
|
|
83
112
|
self.class.engine_initialized = true
|
|
84
113
|
end
|
|
85
|
-
end
|
|
86
114
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def initialize_engine
|
|
91
|
-
end
|
|
92
|
-
@engine_initialized = false
|
|
93
|
-
class << self ; attr_accessor :engine_initialized ; end
|
|
115
|
+
# used to generate unique method names for template compilation
|
|
116
|
+
stamp = (Time.now.to_f * 10000).to_i
|
|
117
|
+
@_prefix = "__tilt_O#{object_id.to_s(16)}T#{stamp.to_s(16)}"
|
|
94
118
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def compile
|
|
100
|
-
if @data.nil?
|
|
101
|
-
@data = @reader.call(self)
|
|
102
|
-
compile!
|
|
103
|
-
end
|
|
119
|
+
# load template data and prepare
|
|
120
|
+
@reader = block || lambda { |t| File.read(@file) }
|
|
121
|
+
@data = @reader.call(self)
|
|
122
|
+
prepare
|
|
104
123
|
end
|
|
105
124
|
|
|
106
125
|
# Render the template in the given scope with the locals specified. If a
|
|
107
126
|
# block is given, it is typically available within the template via
|
|
108
127
|
# +yield+.
|
|
109
128
|
def render(scope=Object.new, locals={}, &block)
|
|
110
|
-
compile
|
|
111
129
|
evaluate scope, locals || {}, &block
|
|
112
130
|
end
|
|
113
131
|
|
|
@@ -127,26 +145,56 @@ module Tilt
|
|
|
127
145
|
end
|
|
128
146
|
|
|
129
147
|
protected
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
#
|
|
148
|
+
# Called once and only once for each template subclass the first time
|
|
149
|
+
# the template class is initialized. This should be used to require the
|
|
150
|
+
# underlying template library and perform any initial setup.
|
|
151
|
+
def initialize_engine
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Do whatever preparation is necessary to setup the underlying template
|
|
155
|
+
# engine. Called immediately after template data is loaded. Instance
|
|
156
|
+
# variables set in this method are available when #evaluate is called.
|
|
133
157
|
#
|
|
134
158
|
# Subclasses must provide an implementation of this method.
|
|
135
|
-
def
|
|
136
|
-
|
|
159
|
+
def prepare
|
|
160
|
+
if respond_to?(:compile!)
|
|
161
|
+
# backward compat with tilt < 0.6; just in case
|
|
162
|
+
warn 'Tilt::Template#compile! is deprecated; implement #prepare instead.'
|
|
163
|
+
compile!
|
|
164
|
+
else
|
|
165
|
+
raise NotImplementedError
|
|
166
|
+
end
|
|
137
167
|
end
|
|
138
168
|
|
|
139
|
-
# Process the template and return the result.
|
|
140
|
-
#
|
|
169
|
+
# Process the template and return the result. When the scope mixes in
|
|
170
|
+
# the Tilt::CompileSite module, the template is compiled to a method and
|
|
171
|
+
# reused given identical locals keys. When the scope object
|
|
172
|
+
# does not mix in the CompileSite module, the template source is
|
|
173
|
+
# evaluated with instance_eval. In any case, template executation
|
|
174
|
+
# is guaranteed to be performed in the scope object with the locals
|
|
175
|
+
# specified and with support for yielding to the block.
|
|
141
176
|
def evaluate(scope, locals, &block)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
177
|
+
if scope.respond_to?(:__tilt__)
|
|
178
|
+
method_name = compiled_method_name(locals.keys.hash)
|
|
179
|
+
if scope.respond_to?(method_name)
|
|
180
|
+
# fast path
|
|
181
|
+
scope.send method_name, locals, &block
|
|
182
|
+
else
|
|
183
|
+
# compile first and then run
|
|
184
|
+
compile_template_method(method_name, locals)
|
|
185
|
+
scope.send method_name, locals, &block
|
|
186
|
+
end
|
|
187
|
+
else
|
|
188
|
+
source, offset = local_assignment_code(locals)
|
|
189
|
+
source = [source, template_source].join("\n")
|
|
190
|
+
scope.instance_eval source, eval_file, line - offset
|
|
191
|
+
end
|
|
145
192
|
end
|
|
146
193
|
|
|
147
194
|
# Return a string containing the (Ruby) source code for the template. The
|
|
148
195
|
# default Template#evaluate implementation requires this method be
|
|
149
|
-
# defined
|
|
196
|
+
# defined and guarantees correct file/line handling, custom scopes, and
|
|
197
|
+
# support for template compilation when the scope object allows it.
|
|
150
198
|
def template_source
|
|
151
199
|
raise NotImplementedError
|
|
152
200
|
end
|
|
@@ -158,6 +206,41 @@ module Tilt
|
|
|
158
206
|
[source.join("\n"), source.length]
|
|
159
207
|
end
|
|
160
208
|
|
|
209
|
+
def compiled_method_name(locals_hash)
|
|
210
|
+
"#{@_prefix}L#{locals_hash.to_s(16).sub('-', 'n')}"
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def compile_template_method(method_name, locals)
|
|
214
|
+
source, offset = local_assignment_code(locals)
|
|
215
|
+
source = [source, template_source].join("\n")
|
|
216
|
+
offset += 1
|
|
217
|
+
|
|
218
|
+
# add the new method
|
|
219
|
+
CompileSite.module_eval <<-RUBY, eval_file, line - offset
|
|
220
|
+
def #{method_name}(locals)
|
|
221
|
+
#{source}
|
|
222
|
+
end
|
|
223
|
+
RUBY
|
|
224
|
+
|
|
225
|
+
# setup a finalizer to remove the newly added method
|
|
226
|
+
ObjectSpace.define_finalizer self,
|
|
227
|
+
Template.compiled_template_method_remover(CompileSite, method_name)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def self.compiled_template_method_remover(site, method_name)
|
|
231
|
+
proc { |oid| garbage_collect_compiled_template_method(site, method_name) }
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def self.garbage_collect_compiled_template_method(site, method_name)
|
|
235
|
+
site.module_eval do
|
|
236
|
+
begin
|
|
237
|
+
remove_method(method_name)
|
|
238
|
+
rescue NameError
|
|
239
|
+
# method was already removed (ruby >= 1.9)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
161
244
|
def require_template_library(name)
|
|
162
245
|
if Thread.list.size > 1
|
|
163
246
|
warn "WARN: tilt autoloading '#{name}' in a non thread-safe way; " +
|
|
@@ -173,7 +256,7 @@ module Tilt
|
|
|
173
256
|
# cache = Tilt::Cache.new
|
|
174
257
|
# cache.fetch(path, line, options) { Tilt.new(path, line, options) }
|
|
175
258
|
#
|
|
176
|
-
# Subsequent invocations return the already
|
|
259
|
+
# Subsequent invocations return the already loaded template object.
|
|
177
260
|
class Cache
|
|
178
261
|
def initialize
|
|
179
262
|
@cache = {}
|
|
@@ -195,7 +278,7 @@ module Tilt
|
|
|
195
278
|
# The template source is evaluated as a Ruby string. The #{} interpolation
|
|
196
279
|
# syntax can be used to generated dynamic output.
|
|
197
280
|
class StringTemplate < Template
|
|
198
|
-
def
|
|
281
|
+
def prepare
|
|
199
282
|
@code = "%Q{#{data}}"
|
|
200
283
|
end
|
|
201
284
|
|
|
@@ -213,8 +296,9 @@ module Tilt
|
|
|
213
296
|
require_template_library 'erb' unless defined? ::ERB
|
|
214
297
|
end
|
|
215
298
|
|
|
216
|
-
def
|
|
217
|
-
@
|
|
299
|
+
def prepare
|
|
300
|
+
@outvar = (options[:outvar] || '_erbout').to_s
|
|
301
|
+
@engine = ::ERB.new(data, options[:safe], options[:trim], @outvar)
|
|
218
302
|
end
|
|
219
303
|
|
|
220
304
|
def template_source
|
|
@@ -222,22 +306,23 @@ module Tilt
|
|
|
222
306
|
end
|
|
223
307
|
|
|
224
308
|
def evaluate(scope, locals, &block)
|
|
225
|
-
|
|
226
|
-
source = [source, template_source].join("\n")
|
|
227
|
-
|
|
228
|
-
original_out_buf =
|
|
229
|
-
scope.instance_variables.any? { |var| var.to_sym == :@_out_buf } &&
|
|
230
|
-
scope.instance_variable_get(:@_out_buf)
|
|
231
|
-
|
|
232
|
-
scope.instance_eval source, eval_file, line - offset
|
|
233
|
-
|
|
234
|
-
output = scope.instance_variable_get(:@_out_buf)
|
|
235
|
-
scope.instance_variable_set(:@_out_buf, original_out_buf)
|
|
236
|
-
|
|
237
|
-
output
|
|
309
|
+
preserve_outvar_value(scope) { super }
|
|
238
310
|
end
|
|
239
311
|
|
|
240
312
|
private
|
|
313
|
+
# Retains the previous value of outvar when configured to use
|
|
314
|
+
# an instance variable. This allows multiple templates to be rendered
|
|
315
|
+
# within the context of an object without overwriting the outvar.
|
|
316
|
+
def preserve_outvar_value(scope)
|
|
317
|
+
if @outvar[0] == ?@
|
|
318
|
+
previous = scope.instance_variable_get(@outvar)
|
|
319
|
+
output = yield
|
|
320
|
+
scope.instance_variable_set(@outvar, previous)
|
|
321
|
+
output
|
|
322
|
+
else
|
|
323
|
+
yield
|
|
324
|
+
end
|
|
325
|
+
end
|
|
241
326
|
|
|
242
327
|
# ERB generates a line to specify the character coding of the generated
|
|
243
328
|
# source in 1.9. Account for this in the line offset.
|
|
@@ -258,13 +343,17 @@ module Tilt
|
|
|
258
343
|
require_template_library 'erubis' unless defined? ::Erubis
|
|
259
344
|
end
|
|
260
345
|
|
|
261
|
-
def
|
|
262
|
-
|
|
346
|
+
def prepare
|
|
347
|
+
@options.merge!(:preamble => false, :postamble => false)
|
|
348
|
+
@outvar = (options.delete(:outvar) || '_erbout').to_s
|
|
263
349
|
@engine = ::Erubis::Eruby.new(data, options)
|
|
264
350
|
end
|
|
265
351
|
|
|
266
|
-
|
|
352
|
+
def template_source
|
|
353
|
+
["#{@outvar} = _buf = ''", @engine.src, "_buf.to_s"].join(";")
|
|
354
|
+
end
|
|
267
355
|
|
|
356
|
+
private
|
|
268
357
|
# Erubis doesn't have ERB's line-off-by-one under 1.9 problem. Override
|
|
269
358
|
# and adjust back.
|
|
270
359
|
if RUBY_VERSION >= '1.9.0'
|
|
@@ -284,15 +373,37 @@ module Tilt
|
|
|
284
373
|
require_template_library 'haml' unless defined? ::Haml::Engine
|
|
285
374
|
end
|
|
286
375
|
|
|
287
|
-
def
|
|
376
|
+
def prepare
|
|
288
377
|
@engine = ::Haml::Engine.new(data, haml_options)
|
|
289
378
|
end
|
|
290
379
|
|
|
291
|
-
|
|
292
|
-
|
|
380
|
+
# Precompiled Haml source. Taken from the precompiled_with_ambles
|
|
381
|
+
# method in Haml::Precompiler:
|
|
382
|
+
# http://github.com/nex3/haml/blob/master/lib/haml/precompiler.rb#L111-126
|
|
383
|
+
def template_source
|
|
384
|
+
@engine.instance_eval do
|
|
385
|
+
<<-RUBY
|
|
386
|
+
_haml_locals = locals
|
|
387
|
+
begin
|
|
388
|
+
extend Haml::Helpers
|
|
389
|
+
_hamlout = @haml_buffer = Haml::Buffer.new(@haml_buffer, #{options_for_buffer.inspect})
|
|
390
|
+
_erbout = _hamlout.buffer
|
|
391
|
+
__in_erb_template = true
|
|
392
|
+
#{precompiled}
|
|
393
|
+
#{precompiled_method_return_value}
|
|
394
|
+
ensure
|
|
395
|
+
@haml_buffer = @haml_buffer.upper
|
|
396
|
+
end
|
|
397
|
+
RUBY
|
|
398
|
+
end
|
|
293
399
|
end
|
|
294
400
|
|
|
295
401
|
private
|
|
402
|
+
def local_assignment_code(locals)
|
|
403
|
+
source, offset = super
|
|
404
|
+
[source, offset + 6]
|
|
405
|
+
end
|
|
406
|
+
|
|
296
407
|
def haml_options
|
|
297
408
|
options.merge(:filename => eval_file, :line => line)
|
|
298
409
|
end
|
|
@@ -309,12 +420,12 @@ module Tilt
|
|
|
309
420
|
require_template_library 'sass' unless defined? ::Sass::Engine
|
|
310
421
|
end
|
|
311
422
|
|
|
312
|
-
def
|
|
423
|
+
def prepare
|
|
313
424
|
@engine = ::Sass::Engine.new(data, sass_options)
|
|
314
425
|
end
|
|
315
426
|
|
|
316
427
|
def evaluate(scope, locals, &block)
|
|
317
|
-
@engine.render
|
|
428
|
+
@output ||= @engine.render
|
|
318
429
|
end
|
|
319
430
|
|
|
320
431
|
private
|
|
@@ -334,7 +445,7 @@ module Tilt
|
|
|
334
445
|
require_template_library 'less' unless defined? ::Less::Engine
|
|
335
446
|
end
|
|
336
447
|
|
|
337
|
-
def
|
|
448
|
+
def prepare
|
|
338
449
|
@engine = ::Less::Engine.new(data)
|
|
339
450
|
end
|
|
340
451
|
|
|
@@ -344,6 +455,7 @@ module Tilt
|
|
|
344
455
|
end
|
|
345
456
|
register 'less', LessTemplate
|
|
346
457
|
|
|
458
|
+
|
|
347
459
|
# Builder template implementation. See:
|
|
348
460
|
# http://builder.rubyforge.org/
|
|
349
461
|
class BuilderTemplate < Template
|
|
@@ -351,7 +463,7 @@ module Tilt
|
|
|
351
463
|
require_template_library 'builder' unless defined?(::Builder)
|
|
352
464
|
end
|
|
353
465
|
|
|
354
|
-
def
|
|
466
|
+
def prepare
|
|
355
467
|
end
|
|
356
468
|
|
|
357
469
|
def evaluate(scope, locals, &block)
|
|
@@ -390,7 +502,7 @@ module Tilt
|
|
|
390
502
|
require_template_library 'liquid' unless defined? ::Liquid::Template
|
|
391
503
|
end
|
|
392
504
|
|
|
393
|
-
def
|
|
505
|
+
def prepare
|
|
394
506
|
@engine = ::Liquid::Template.parse(data)
|
|
395
507
|
end
|
|
396
508
|
|
|
@@ -400,9 +512,8 @@ module Tilt
|
|
|
400
512
|
scope = scope.to_h.inject({}){ |h,(k,v)| h[k.to_s] = v ; h }
|
|
401
513
|
locals = scope.merge(locals)
|
|
402
514
|
end
|
|
403
|
-
# TODO: Is it possible to lazy yield ?
|
|
404
515
|
locals['yield'] = block.nil? ? '' : yield
|
|
405
|
-
locals['content'] =
|
|
516
|
+
locals['content'] = locals['yield']
|
|
406
517
|
@engine.render(locals)
|
|
407
518
|
end
|
|
408
519
|
end
|
|
@@ -424,7 +535,7 @@ module Tilt
|
|
|
424
535
|
require_template_library 'rdiscount' unless defined? ::RDiscount
|
|
425
536
|
end
|
|
426
537
|
|
|
427
|
-
def
|
|
538
|
+
def prepare
|
|
428
539
|
@engine = RDiscount.new(data, *flags)
|
|
429
540
|
end
|
|
430
541
|
|
|
@@ -437,22 +548,22 @@ module Tilt
|
|
|
437
548
|
register 'md', RDiscountTemplate
|
|
438
549
|
|
|
439
550
|
|
|
440
|
-
# RedCloth implementation. See:
|
|
441
|
-
# http://redcloth.org/
|
|
442
|
-
class RedClothTemplate < Template
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
551
|
+
# RedCloth implementation. See:
|
|
552
|
+
# http://redcloth.org/
|
|
553
|
+
class RedClothTemplate < Template
|
|
554
|
+
def initialize_engine
|
|
555
|
+
require_template_library 'redcloth' unless defined? ::RedCloth
|
|
556
|
+
end
|
|
446
557
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
558
|
+
def prepare
|
|
559
|
+
@engine = RedCloth.new(data)
|
|
560
|
+
end
|
|
450
561
|
|
|
451
|
-
|
|
452
|
-
|
|
562
|
+
def evaluate(scope, locals, &block)
|
|
563
|
+
@engine.to_html
|
|
564
|
+
end
|
|
453
565
|
end
|
|
454
|
-
|
|
455
|
-
register 'textile', RedClothTemplate
|
|
566
|
+
register 'textile', RedClothTemplate
|
|
456
567
|
|
|
457
568
|
|
|
458
569
|
# Mustache is written and maintained by Chris Wanstrath. See:
|
|
@@ -468,11 +579,12 @@ register 'textile', RedClothTemplate
|
|
|
468
579
|
require_template_library 'mustache' unless defined? ::Mustache
|
|
469
580
|
end
|
|
470
581
|
|
|
471
|
-
def
|
|
582
|
+
def prepare
|
|
472
583
|
Mustache.view_namespace = options[:namespace]
|
|
584
|
+
Mustache.view_path = options[:view_path] || options[:mustaches]
|
|
473
585
|
@engine = options[:view] || Mustache.view_class(name)
|
|
474
586
|
options.each do |key, value|
|
|
475
|
-
next if %w[view namespace mustaches].include?(key.to_s)
|
|
587
|
+
next if %w[view view_path namespace mustaches].include?(key.to_s)
|
|
476
588
|
@engine.send("#{key}=", value) if @engine.respond_to? "#{key}="
|
|
477
589
|
end
|
|
478
590
|
end
|
|
@@ -501,6 +613,7 @@ register 'textile', RedClothTemplate
|
|
|
501
613
|
end
|
|
502
614
|
register 'mustache', MustacheTemplate
|
|
503
615
|
|
|
616
|
+
|
|
504
617
|
# RDoc template. See:
|
|
505
618
|
# http://rdoc.rubyforge.org/
|
|
506
619
|
#
|
|
@@ -515,7 +628,7 @@ register 'textile', RedClothTemplate
|
|
|
515
628
|
end
|
|
516
629
|
end
|
|
517
630
|
|
|
518
|
-
def
|
|
631
|
+
def prepare
|
|
519
632
|
markup = RDoc::Markup::ToHtml.new
|
|
520
633
|
@engine = markup.convert(data)
|
|
521
634
|
end
|
|
@@ -525,4 +638,22 @@ register 'textile', RedClothTemplate
|
|
|
525
638
|
end
|
|
526
639
|
end
|
|
527
640
|
register 'rdoc', RDocTemplate
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
# CoffeeScript info:
|
|
644
|
+
# http://jashkenas.github.com/coffee-script/
|
|
645
|
+
class CoffeeTemplate < Template
|
|
646
|
+
def initialize_engine
|
|
647
|
+
require_template_library 'coffee-script' unless defined? ::CoffeeScript
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
def prepare
|
|
651
|
+
@engine = ::CoffeeScript::compile(data, options)
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
def evaluate(scope, locals, &block)
|
|
655
|
+
@engine
|
|
656
|
+
end
|
|
657
|
+
end
|
|
658
|
+
register 'coffee', CoffeeTemplate
|
|
528
659
|
end
|
|
@@ -9,7 +9,7 @@ begin
|
|
|
9
9
|
assert_equal Tilt::BuilderTemplate, Tilt['test.xml.builder']
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
test "
|
|
12
|
+
test "preparing and evaluating the template on #render" do
|
|
13
13
|
template = Tilt::BuilderTemplate.new { |t| "xml.em 'Hello World!'" }
|
|
14
14
|
assert_equal "<em>Hello World!</em>\n", template.render
|
|
15
15
|
end
|