Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 755 lines (641 sloc) 22.853 kb
f916a5c Ryan Tomayko compiled template method names use MD5 and lookup hash
authored
1 require 'digest/md5'
2
137cd54 Ryan Tomayko Tilt!
authored
3 module Tilt
a427c1d Ryan Tomayko 0.8 release
authored
4 VERSION = '0.8'
531c141 Ryan Tomayko add Tilt::VERSION and update gemspec
authored
5
137cd54 Ryan Tomayko Tilt!
authored
6 @template_mappings = {}
7
b748424 Ryan Tomayko misc doc comment fixes
authored
8 # Hash of template path pattern => template implementation class mappings.
c9b44a8 Ryan Tomayko Tilt.mappings exposes the file pattern -> class mappings Hash
authored
9 def self.mappings
10 @template_mappings
11 end
12
137cd54 Ryan Tomayko Tilt!
authored
13 # Register a template implementation by file extension.
14 def self.register(ext, template_class)
3721ba7 Scott Taylor Allow Template::register's file extensions to be given as a symbol
smtlaissezfaire authored
15 ext = ext.to_s.sub(/^\./, '')
c9b44a8 Ryan Tomayko Tilt.mappings exposes the file pattern -> class mappings Hash
authored
16 mappings[ext.downcase] = template_class
137cd54 Ryan Tomayko Tilt!
authored
17 end
18
00ce3f7 Justin Knowlden Cleaned up Tilt[](ext) method because the redundancy was bothering me. B...
gus authored
19 def self.registered?(ext)
20 mappings.key?(ext.downcase)
21 end
22
137cd54 Ryan Tomayko Tilt!
authored
23 # Create a new template for the given file using the file's extension
24 # to determine the the template mapping.
25 def self.new(file, line=nil, options={}, &block)
7587c3d Ryan Tomayko allow templates to be registered for full paths
authored
26 if template_class = self[file]
137cd54 Ryan Tomayko Tilt!
authored
27 template_class.new(file, line, options, &block)
28 else
29 fail "No template engine registered for #{File.basename(file)}"
30 end
31 end
32
b748424 Ryan Tomayko misc doc comment fixes
authored
33 # Lookup a template class for the given filename or file
137cd54 Ryan Tomayko Tilt!
authored
34 # extension. Return nil when no implementation is found.
7587c3d Ryan Tomayko allow templates to be registered for full paths
authored
35 def self.[](file)
00ce3f7 Justin Knowlden Cleaned up Tilt[](ext) method because the redundancy was bothering me. B...
gus authored
36 pattern = file.to_s.downcase
37 unless registered?(pattern)
38 pattern = File.basename(pattern)
39 pattern.sub!(/^[^.]*\.?/, '') until (pattern.empty? || registered?(pattern))
137cd54 Ryan Tomayko Tilt!
authored
40 end
00ce3f7 Justin Knowlden Cleaned up Tilt[](ext) method because the redundancy was bothering me. B...
gus authored
41 @template_mappings[pattern]
137cd54 Ryan Tomayko Tilt!
authored
42 end
43
4b91c5d Ryan Tomayko shared Tilt::CompileSite mixin instead of passing site to new
authored
44 # Mixin allowing template compilation on scope objects.
45 #
46 # Including this module in scope objects passed to Template#render
47 # causes template source to be compiled to methods the first time they're
48 # used. This can yield significant (5x-10x) performance increases for
49 # templates that support it (ERB, Erubis, Builder).
52ed26c Ryan Tomayko Tilt.enable_global_compile_site! - USE AT YOUR OWN RISK
authored
50 #
4b91c5d Ryan Tomayko shared Tilt::CompileSite mixin instead of passing site to new
authored
51 # It's also possible (though not recommended) to include this module in
52 # Object to enable template compilation globally. The downside is that
53 # the template methods will polute the global namespace and could lead to
54 # unexpected behavior.
55 module CompileSite
56 def __tilt__
57 end
52ed26c Ryan Tomayko Tilt.enable_global_compile_site! - USE AT YOUR OWN RISK
authored
58 end
59
137cd54 Ryan Tomayko Tilt!
authored
60 # Base class for template implementations. Subclasses must implement
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
61 # the #prepare method and one of the #evaluate or #template_source
137cd54 Ryan Tomayko Tilt!
authored
62 # methods.
93cc8fb Ryan Tomayko Rename "AbstractTemplate" to just "Template"
authored
63 class Template
51ef07e Ryan Tomayko Minor doc additions
authored
64 # Template source; loaded from a file or given directly.
137cd54 Ryan Tomayko Tilt!
authored
65 attr_reader :data
66
67 # The name of the file where the template data was loaded from.
68 attr_reader :file
69
70 # The line number in #file where template data was loaded from.
71 attr_reader :line
72
73 # A Hash of template engine specific options. This is passed directly
74 # to the underlying engine and is not used by the generic template
75 # interface.
76 attr_reader :options
77
b82adf2 Ryan Tomayko misc cleanup of initialize_engine related methods
authored
78 # Used to determine if this class's initialize_engine method has
79 # been called yet.
80 @engine_initialized = false
81 class << self
82 attr_accessor :engine_initialized
83 alias engine_initialized? engine_initialized
84 end
85
137cd54 Ryan Tomayko Tilt!
authored
86 # Create a new template with the file, line, and options specified. By
ad91ea1 Ryan Tomayko all Template.new args are optional and may be given in any order
authored
87 # default, template data is read from the file. When a block is given,
88 # it should read template data and return as a String. When file is nil,
89 # a block is required.
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
90 #
ad91ea1 Ryan Tomayko all Template.new args are optional and may be given in any order
authored
91 # All arguments are optional.
137cd54 Ryan Tomayko Tilt!
authored
92 def initialize(file=nil, line=1, options={}, &block)
4b91c5d Ryan Tomayko shared Tilt::CompileSite mixin instead of passing site to new
authored
93 @file, @line, @options = nil, 1, {}
ad91ea1 Ryan Tomayko all Template.new args are optional and may be given in any order
authored
94
4b91c5d Ryan Tomayko shared Tilt::CompileSite mixin instead of passing site to new
authored
95 [options, line, file].compact.each do |arg|
ad91ea1 Ryan Tomayko all Template.new args are optional and may be given in any order
authored
96 case
97 when arg.respond_to?(:to_str) ; @file = arg.to_str
98 when arg.respond_to?(:to_int) ; @line = arg.to_int
99 when arg.respond_to?(:to_hash) ; @options = arg.to_hash
100 else raise TypeError
101 end
102 end
103
104 raise ArgumentError, "file or block required" if (@file || block).nil?
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
105
b82adf2 Ryan Tomayko misc cleanup of initialize_engine related methods
authored
106 # call the initialize_engine method if this is the very first time
107 # an instance of this class has been created.
108 if !self.class.engine_initialized?
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
109 initialize_engine
110 self.class.engine_initialized = true
111 end
3baad66 Ryan Tomayko load template in initializer instead of on first render
authored
112
a69686d Ryan Tomayko tighten up compiled method names a bit
authored
113 # used to generate unique method names for template compilation
f916a5c Ryan Tomayko compiled template method names use MD5 and lookup hash
authored
114 @stamp = (Time.now.to_f * 10000).to_i
115 @compiled_method_names = {}
a69686d Ryan Tomayko tighten up compiled method names a bit
authored
116
117 # load template data and prepare
ad91ea1 Ryan Tomayko all Template.new args are optional and may be given in any order
authored
118 @reader = block || lambda { |t| File.read(@file) }
3baad66 Ryan Tomayko load template in initializer instead of on first render
authored
119 @data = @reader.call(self)
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
120 prepare
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
121 end
122
c1cb0de Ryan Tomayko Template#compile method is like #compile! but runs once
authored
123 # Render the template in the given scope with the locals specified. If a
124 # block is given, it is typically available within the template via
125 # +yield+.
126 def render(scope=Object.new, locals={}, &block)
137cd54 Ryan Tomayko Tilt!
authored
127 evaluate scope, locals || {}, &block
128 end
129
60c8338 Ryan Tomayko Template#basename and Template#name
authored
130 # The basename of the template file.
131 def basename(suffix='')
132 File.basename(file, suffix) if file
133 end
134
135 # The template file's basename with all extensions chomped off.
136 def name
137 basename.split('.', 2).first if basename
138 end
139
137cd54 Ryan Tomayko Tilt!
authored
140 # The filename used in backtraces to describe the template.
141 def eval_file
df02cf8 Ryan Tomayko #eval_file takes subclass #file implementations into account
authored
142 file || '(__TEMPLATE__)'
137cd54 Ryan Tomayko Tilt!
authored
143 end
144
145 protected
b82adf2 Ryan Tomayko misc cleanup of initialize_engine related methods
authored
146 # Called once and only once for each template subclass the first time
147 # the template class is initialized. This should be used to require the
148 # underlying template library and perform any initial setup.
149 def initialize_engine
150 end
151
c8b818a Ryan Tomayko ditto require_template_library
authored
152 # Like Kernel::require but issues a warning urging a manual require when
153 # running under a threaded environment.
154 def require_template_library(name)
155 if Thread.list.size > 1
156 warn "WARN: tilt autoloading '#{name}' in a non thread-safe way; " +
157 "explicit require '#{name}' suggested."
158 end
159 require name
160 end
161
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
162 # Do whatever preparation is necessary to setup the underlying template
163 # engine. Called immediately after template data is loaded. Instance
164 # variables set in this method are available when #evaluate is called.
51ef07e Ryan Tomayko Minor doc additions
authored
165 #
166 # Subclasses must provide an implementation of this method.
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
167 def prepare
168 if respond_to?(:compile!)
169 # backward compat with tilt < 0.6; just in case
1882f27 Ryan Tomayko warn if Template subclass implements #compile!
authored
170 warn 'Tilt::Template#compile! is deprecated; implement #prepare instead.'
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
171 compile!
172 else
173 raise NotImplementedError
174 end
137cd54 Ryan Tomayko Tilt!
authored
175 end
176
420306c Ryan Tomayko don't lie
authored
177 # Process the template and return the result. When the scope mixes in
178 # the Tilt::CompileSite module, the template is compiled to a method and
179 # reused given identical locals keys. When the scope object
180 # does not mix in the CompileSite module, the template source is
4c974cf Ryan Tomayko compile template only when compile_site module given
authored
181 # evaluated with instance_eval. In any case, template executation
182 # is guaranteed to be performed in the scope object with the locals
183 # specified and with support for yielding to the block.
137cd54 Ryan Tomayko Tilt!
authored
184 def evaluate(scope, locals, &block)
4b91c5d Ryan Tomayko shared Tilt::CompileSite mixin instead of passing site to new
authored
185 if scope.respond_to?(:__tilt__)
f916a5c Ryan Tomayko compiled template method names use MD5 and lookup hash
authored
186 method_name = compiled_method_name(locals.keys)
4c974cf Ryan Tomayko compile template only when compile_site module given
authored
187 if scope.respond_to?(method_name)
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
188 scope.send(method_name, locals, &block)
4c974cf Ryan Tomayko compile template only when compile_site module given
authored
189 else
190 compile_template_method(method_name, locals)
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
191 scope.send(method_name, locals, &block)
4c974cf Ryan Tomayko compile template only when compile_site module given
authored
192 end
f75a8c9 Ryan Tomayko basic support for compiling templates to methods on a mixin
authored
193 else
7a241ab Ryan Tomayko fix issues with source eval templates under JRuby
authored
194 evaluate_source(scope, locals, &block)
f75a8c9 Ryan Tomayko basic support for compiling templates to methods on a mixin
authored
195 end
137cd54 Ryan Tomayko Tilt!
authored
196 end
197
e801634 Ryan Tomayko make precompiled template source methods more descriptive
authored
198 # Generates all template source by combining the preamble, template, and
199 # postamble and returns a two-tuple of the form: [source, offset], where
200 # source is the string containing (Ruby) source code for the template and
201 # offset is the integer line offset where line reporting should begin.
202 #
203 # Template subclasses may override this method when they need complete
204 # control over source generation or want to adjust the default line
205 # offset. In most cases, overriding the #precompiled_template method is
206 # easier and more appropriate.
207 def precompiled(locals)
208 preamble = precompiled_preamble(locals)
209 parts = [
210 preamble,
211 precompiled_template(locals),
212 precompiled_postamble(locals)
213 ]
214 [parts.join("\n"), preamble.count("\n") + 1]
215 end
216
217 # A string containing the (Ruby) source code for the template. The
218 # default Template#evaluate implementation requires either this method
219 # or the #precompiled method be overridden. When defined, the base
220 # Template guarantees correct file/line handling, locals support, custom
221 # scopes, and support for template compilation when the scope object
222 # allows it.
223 def precompiled_template(locals)
137cd54 Ryan Tomayko Tilt!
authored
224 raise NotImplementedError
225 end
226
e801634 Ryan Tomayko make precompiled template source methods more descriptive
authored
227 # Generates preamble code for initializing template state, and performing
228 # locals assignment. The default implementation performs locals
229 # assignment only. Lines included in the preamble are subtracted from the
230 # source line offset, so adding code to the preamble does not effect line
231 # reporting in Kernel::caller and backtraces.
232 def precompiled_preamble(locals)
233 locals.map { |k,v| "#{k} = locals[:#{k}]" }.join("\n")
234 end
235
236 # Generates postamble code for the precompiled template source. The
237 # string returned from this method is appended to the precompiled
238 # template source.
239 def precompiled_postamble(locals)
240 ''
137cd54 Ryan Tomayko Tilt!
authored
241 end
b8381e1 Ryan Tomayko require_template_library is private
authored
242
f916a5c Ryan Tomayko compiled template method names use MD5 and lookup hash
authored
243 # The unique compiled method name for the locals keys provided.
244 def compiled_method_name(locals_keys)
245 @compiled_method_names[locals_keys] ||=
246 generate_compiled_method_name(locals_keys)
f53c491 Ryan Tomayko fix method checks under ruby 1.9 (string vs. symbol)
authored
247 end
248
dceb4a4 Ryan Tomayko document local_assignment_code and move to protected
authored
249 private
7a241ab Ryan Tomayko fix issues with source eval templates under JRuby
authored
250 # Evaluate the template source in the context of the scope object.
251 def evaluate_source(scope, locals, &block)
252 source, offset = precompiled(locals)
253 scope.instance_eval(source, eval_file, line - offset)
254 end
255
256 # JRuby doesn't allow Object#instance_eval to yield to the block it's
257 # closed over. This is by design and (ostensibly) something that will
258 # change in MRI, though no current MRI version tested (1.8.6 - 1.9.2)
259 # exhibits the behavior. More info here:
260 #
261 # http://jira.codehaus.org/browse/JRUBY-2599
262 #
263 # Additionally, JRuby's eval line reporting is off by one compared to
264 # all MRI versions tested.
265 #
266 # We redefine evaluate_source to work around both issues.
267 if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
268 undef evaluate_source
269 def evaluate_source(scope, locals, &block)
270 source, offset = precompiled(locals)
271 file, lineno = eval_file, (line - offset) - 1
272 scope.instance_eval { Kernel::eval(source, binding, file, lineno) }
273 end
274 end
275
f916a5c Ryan Tomayko compiled template method names use MD5 and lookup hash
authored
276 def generate_compiled_method_name(locals_keys)
277 parts = [object_id, @stamp] + locals_keys.map { |k| k.to_s }.sort
278 digest = Digest::MD5.hexdigest(parts.join(':'))
279 "__tilt_#{digest}"
280 end
281
f75a8c9 Ryan Tomayko basic support for compiling templates to methods on a mixin
authored
282 def compile_template_method(method_name, locals)
e801634 Ryan Tomayko make precompiled template source methods more descriptive
authored
283 source, offset = precompiled(locals)
4c974cf Ryan Tomayko compile template only when compile_site module given
authored
284 offset += 1
4b91c5d Ryan Tomayko shared Tilt::CompileSite mixin instead of passing site to new
authored
285 CompileSite.module_eval <<-RUBY, eval_file, line - offset
4c974cf Ryan Tomayko compile template only when compile_site module given
authored
286 def #{method_name}(locals)
287 #{source}
288 end
289 RUBY
67f4e96 Ryan Tomayko finalizer removes compiled methods
authored
290
291 ObjectSpace.define_finalizer self,
8d857f9 Ryan Tomayko test compiled method garbage collection
authored
292 Template.compiled_template_method_remover(CompileSite, method_name)
67f4e96 Ryan Tomayko finalizer removes compiled methods
authored
293 end
294
8d857f9 Ryan Tomayko test compiled method garbage collection
authored
295 def self.compiled_template_method_remover(site, method_name)
296 proc { |oid| garbage_collect_compiled_template_method(site, method_name) }
297 end
298
299 def self.garbage_collect_compiled_template_method(site, method_name)
300 site.module_eval do
301 begin
302 remove_method(method_name)
303 rescue NameError
304 # method was already removed (ruby >= 1.9)
67f4e96 Ryan Tomayko finalizer removes compiled methods
authored
305 end
306 end
f75a8c9 Ryan Tomayko basic support for compiling templates to methods on a mixin
authored
307 end
137cd54 Ryan Tomayko Tilt!
authored
308 end
309
3435557 Ryan Tomayko better Tilt::Cache with specs
authored
310 # Extremely simple template cache implementation. Calling applications
311 # create a Tilt::Cache instance and use #fetch with any set of hashable
312 # arguments (such as those to Tilt.new):
313 # cache = Tilt::Cache.new
314 # cache.fetch(path, line, options) { Tilt.new(path, line, options) }
315 #
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
316 # Subsequent invocations return the already loaded template object.
d169230 Ryan Tomayko Dead simple template cache implementation
authored
317 class Cache
318 def initialize
319 @cache = {}
320 end
321
322 def fetch(*key)
323 @cache[key] ||= yield
324 end
325
326 def clear
327 @cache = {}
328 end
329 end
330
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
331
d169230 Ryan Tomayko Dead simple template cache implementation
authored
332 # Template Implementations ================================================
333
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
334
137cd54 Ryan Tomayko Tilt!
authored
335 # The template source is evaluated as a Ruby string. The #{} interpolation
336 # syntax can be used to generated dynamic output.
93cc8fb Ryan Tomayko Rename "AbstractTemplate" to just "Template"
authored
337 class StringTemplate < Template
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
338 def prepare
137cd54 Ryan Tomayko Tilt!
authored
339 @code = "%Q{#{data}}"
340 end
341
e801634 Ryan Tomayko make precompiled template source methods more descriptive
authored
342 def precompiled_template(locals)
137cd54 Ryan Tomayko Tilt!
authored
343 @code
344 end
345 end
346 register 'str', StringTemplate
347
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
348
137cd54 Ryan Tomayko Tilt!
authored
349 # ERB template implementation. See:
350 # http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html
93cc8fb Ryan Tomayko Rename "AbstractTemplate" to just "Template"
authored
351 class ERBTemplate < Template
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
352 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
353 return if defined? ::ERB
354 require_template_library 'erb'
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
355 end
356
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
357 def prepare
c661c9d Ryan Tomayko make ERB outvar name an option
authored
358 @outvar = (options[:outvar] || '_erbout').to_s
359 @engine = ::ERB.new(data, options[:safe], options[:trim], @outvar)
137cd54 Ryan Tomayko Tilt!
authored
360 end
361
bc66c37 Ryan Tomayko ERB and Erubis templates implement new precompiled methods
authored
362 def precompiled_template(locals)
137cd54 Ryan Tomayko Tilt!
authored
363 @engine.src
364 end
0d49ccc Ryan Tomayko Fix ERB backtrace line numbers off by 1 under Ruby 1.9
authored
365
bc66c37 Ryan Tomayko ERB and Erubis templates implement new precompiled methods
authored
366 def precompiled_preamble(locals)
367 <<-RUBY
368 begin
369 __original_outvar = #{@outvar} if defined?(#{@outvar})
370 #{super}
371 RUBY
ddeb087 Ryan Tomayko Implement ERB @_out_buf hackery
authored
372 end
373
bc66c37 Ryan Tomayko ERB and Erubis templates implement new precompiled methods
authored
374 def precompiled_postamble(locals)
375 <<-RUBY
376 #{super}
377 ensure
378 #{@outvar} = __original_outvar
379 end
380 RUBY
c661c9d Ryan Tomayko make ERB outvar name an option
authored
381 end
0d49ccc Ryan Tomayko Fix ERB backtrace line numbers off by 1 under Ruby 1.9
authored
382
383 # ERB generates a line to specify the character coding of the generated
384 # source in 1.9. Account for this in the line offset.
385 if RUBY_VERSION >= '1.9.0'
bc66c37 Ryan Tomayko ERB and Erubis templates implement new precompiled methods
authored
386 def precompiled(locals)
0d49ccc Ryan Tomayko Fix ERB backtrace line numbers off by 1 under Ruby 1.9
authored
387 source, offset = super
388 [source, offset + 1]
389 end
390 end
137cd54 Ryan Tomayko Tilt!
authored
391 end
bc66c37 Ryan Tomayko ERB and Erubis templates implement new precompiled methods
authored
392
137cd54 Ryan Tomayko Tilt!
authored
393 %w[erb rhtml].each { |ext| register ext, ERBTemplate }
394
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
395
47a5407 Dylan Egan ERubis template implementation
dylanegan authored
396 # Erubis template implementation. See:
397 # http://www.kuwata-lab.com/erubis/
313b4d4 Geoff Buesing Erubis :engine_class and :escape_html options
gbuesing authored
398 #
209eddc Ryan Tomayko whitespace errors
authored
399 # ErubisTemplate supports the following additional options, which are not
313b4d4 Geoff Buesing Erubis :engine_class and :escape_html options
gbuesing authored
400 # passed down to the Erubis engine:
401 #
402 # :engine_class allows you to specify a custom engine class to use
403 # instead of the default (which is ::Erubis::Eruby).
404 #
405 # :escape_html when true, ::Erubis::EscapedEruby will be used as
406 # the engine class instead of the default. All content
407 # within <%= %> blocks will be automatically html escaped.
47a5407 Dylan Egan ERubis template implementation
dylanegan authored
408 class ErubisTemplate < ERBTemplate
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
409 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
410 return if defined? ::Erubis
411 require_template_library 'erubis'
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
412 end
413
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
414 def prepare
d281f59 Ryan Tomayko make Erubis outvar customizable as well
authored
415 @options.merge!(:preamble => false, :postamble => false)
416 @outvar = (options.delete(:outvar) || '_erbout').to_s
313b4d4 Geoff Buesing Erubis :engine_class and :escape_html options
gbuesing authored
417 engine_class = options.delete(:engine_class)
418 engine_class = ::Erubis::EscapedEruby if options.delete(:escape_html)
419 @engine = (engine_class || ::Erubis::Eruby).new(data, options)
47a5407 Dylan Egan ERubis template implementation
dylanegan authored
420 end
5af596f Ryan Tomayko fix line off by one issue in Erubis under 1.9
authored
421
bc66c37 Ryan Tomayko ERB and Erubis templates implement new precompiled methods
authored
422 def precompiled_preamble(locals)
423 [super, "#{@outvar} = _buf = ''"].join("\n")
d281f59 Ryan Tomayko make Erubis outvar customizable as well
authored
424 end
5af596f Ryan Tomayko fix line off by one issue in Erubis under 1.9
authored
425
bc66c37 Ryan Tomayko ERB and Erubis templates implement new precompiled methods
authored
426 def precompiled_postamble(locals)
427 ["_buf", super].join("\n")
428 end
429
430 # Erubis doesn't have ERB's line-off-by-one under 1.9 problem.
431 # Override and adjust back.
5af596f Ryan Tomayko fix line off by one issue in Erubis under 1.9
authored
432 if RUBY_VERSION >= '1.9.0'
bc66c37 Ryan Tomayko ERB and Erubis templates implement new precompiled methods
authored
433 def precompiled(locals)
5af596f Ryan Tomayko fix line off by one issue in Erubis under 1.9
authored
434 source, offset = super
435 [source, offset - 1]
436 end
437 end
47a5407 Dylan Egan ERubis template implementation
dylanegan authored
438 end
439 register 'erubis', ErubisTemplate
440
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
441
137cd54 Ryan Tomayko Tilt!
authored
442 # Haml template implementation. See:
443 # http://haml.hamptoncatlin.com/
93cc8fb Ryan Tomayko Rename "AbstractTemplate" to just "Template"
authored
444 class HamlTemplate < Template
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
445 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
446 return if defined? ::Haml::Engine
447 require_template_library 'haml'
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
448 end
449
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
450 def prepare
ad18bfc Ryan Tomayko Haml templates implement new precompiled methods
authored
451 options = @options.merge(:filename => eval_file, :line => line)
452 @engine = ::Haml::Engine.new(data, options)
137cd54 Ryan Tomayko Tilt!
authored
453 end
454
af892d9 Ryan Tomayko HamlTemplate falls back to eval mode if haml version is too old
authored
455 def evaluate(scope, locals, &block)
456 if @engine.respond_to?(:precompiled_method_return_value, true)
457 super
458 else
459 @engine.render(scope, locals, &block)
460 end
461 end
462
5e0c907 Ryan Tomayko Haml generates template_source and can be used with compiled templates
authored
463 # Precompiled Haml source. Taken from the precompiled_with_ambles
464 # method in Haml::Precompiler:
465 # http://github.com/nex3/haml/blob/master/lib/haml/precompiler.rb#L111-126
ad18bfc Ryan Tomayko Haml templates implement new precompiled methods
authored
466 def precompiled_template(locals)
467 @engine.precompiled
468 end
469
470 def precompiled_preamble(locals)
471 local_assigns = super
5e0c907 Ryan Tomayko Haml generates template_source and can be used with compiled templates
authored
472 @engine.instance_eval do
473 <<-RUBY
474 begin
475 extend Haml::Helpers
476 _hamlout = @haml_buffer = Haml::Buffer.new(@haml_buffer, #{options_for_buffer.inspect})
477 _erbout = _hamlout.buffer
478 __in_erb_template = true
ad18bfc Ryan Tomayko Haml templates implement new precompiled methods
authored
479 _haml_locals = locals
480 #{local_assigns}
481 RUBY
482 end
483 end
484
485 def precompiled_postamble(locals)
486 @engine.instance_eval do
487 <<-RUBY
5e0c907 Ryan Tomayko Haml generates template_source and can be used with compiled templates
authored
488 #{precompiled_method_return_value}
489 ensure
490 @haml_buffer = @haml_buffer.upper
491 end
492 RUBY
493 end
137cd54 Ryan Tomayko Tilt!
authored
494 end
495 end
496 register 'haml', HamlTemplate
497
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
498
137cd54 Ryan Tomayko Tilt!
authored
499 # Sass template implementation. See:
500 # http://haml.hamptoncatlin.com/
501 #
502 # Sass templates do not support object scopes, locals, or yield.
93cc8fb Ryan Tomayko Rename "AbstractTemplate" to just "Template"
authored
503 class SassTemplate < Template
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
504 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
505 return if defined? ::Sass::Engine
506 require_template_library 'sass'
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
507 end
508
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
509 def prepare
137cd54 Ryan Tomayko Tilt!
authored
510 @engine = ::Sass::Engine.new(data, sass_options)
511 end
512
513 def evaluate(scope, locals, &block)
e6b1ff1 Ryan Tomayko no need to render sass more than once (I think)
authored
514 @output ||= @engine.render
137cd54 Ryan Tomayko Tilt!
authored
515 end
516
517 private
518 def sass_options
519 options.merge(:filename => eval_file, :line => line)
520 end
521 end
522 register 'sass', SassTemplate
523
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
524
667bbd6 Ben Schwarz Added lesscss implementation
benschwarz authored
525 # Lessscss template implementation. See:
526 # http://lesscss.org/
527 #
528 # Less templates do not support object scopes, locals, or yield.
529 class LessTemplate < Template
530 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
531 return if defined? ::Less::Engine
532 require_template_library 'less'
667bbd6 Ben Schwarz Added lesscss implementation
benschwarz authored
533 end
534
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
535 def prepare
667bbd6 Ben Schwarz Added lesscss implementation
benschwarz authored
536 @engine = ::Less::Engine.new(data)
537 end
538
539 def evaluate(scope, locals, &block)
540 @engine.to_css
541 end
542 end
543 register 'less', LessTemplate
4d4b933 Ryan Tomayko whitespace error - go stand in the corner benschwarz
authored
544
3a6e53f Ryan Tomayko Merge precompiled methods into master
authored
545
137cd54 Ryan Tomayko Tilt!
authored
546 # Builder template implementation. See:
547 # http://builder.rubyforge.org/
93cc8fb Ryan Tomayko Rename "AbstractTemplate" to just "Template"
authored
548 class BuilderTemplate < Template
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
549 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
550 return if defined?(::Builder)
551 require_template_library 'builder'
137cd54 Ryan Tomayko Tilt!
authored
552 end
553
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
554 def prepare
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
555 end
556
137cd54 Ryan Tomayko Tilt!
authored
557 def evaluate(scope, locals, &block)
558 xml = ::Builder::XmlMarkup.new(:indent => 2)
559 if data.respond_to?(:to_str)
560 locals[:xml] = xml
561 super(scope, locals, &block)
562 elsif data.kind_of?(Proc)
563 data.call(xml)
564 end
565 xml.target!
566 end
567
fa40455 Ryan Tomayko Builder templates implement new precompiled methods
authored
568 def precompiled_template(locals)
137cd54 Ryan Tomayko Tilt!
authored
569 data.to_str
570 end
571 end
572 register 'builder', BuilderTemplate
c3d166f Ryan Tomayko Add Liquid implementation (limited)
authored
573
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
574
c3d166f Ryan Tomayko Add Liquid implementation (limited)
authored
575 # Liquid template implementation. See:
576 # http://liquid.rubyforge.org/
577 #
50e4b3d 7rans add scope support to LiquidTemplate via #to_h
trans authored
578 # Liquid is designed to be a *safe* template system and threfore
579 # does not provide direct access to execuatable scopes. In order to
580 # support a +scope+, the +scope+ must be able to represent itself
581 # as a hash by responding to #to_h. If the +scope+ does not respond
582 # to #to_h it will be ignored.
583 #
584 # LiquidTemplate does not support yield blocks.
d0195ed Ryan Tomayko Warn when lazy loading template libraries
authored
585 #
586 # It's suggested that your program require 'liquid' at load
587 # time when using this template engine.
93cc8fb Ryan Tomayko Rename "AbstractTemplate" to just "Template"
authored
588 class LiquidTemplate < Template
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
589 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
590 return if defined? ::Liquid::Template
591 require_template_library 'liquid'
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
592 end
593
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
594 def prepare
c3d166f Ryan Tomayko Add Liquid implementation (limited)
authored
595 @engine = ::Liquid::Template.parse(data)
596 end
597
598 def evaluate(scope, locals, &block)
50e4b3d 7rans add scope support to LiquidTemplate via #to_h
trans authored
599 locals = locals.inject({}){ |h,(k,v)| h[k.to_s] = v ; h }
600 if scope.respond_to?(:to_h)
601 scope = scope.to_h.inject({}){ |h,(k,v)| h[k.to_s] = v ; h }
602 locals = scope.merge(locals)
603 end
1cb1ea0 yield support for Liquid
bry4n authored
604 locals['yield'] = block.nil? ? '' : yield
3f69cb4 Ryan Tomayko no sense in yielding twice in liquid template
authored
605 locals['content'] = locals['yield']
c3d166f Ryan Tomayko Add Liquid implementation (limited)
authored
606 @engine.render(locals)
607 end
608 end
609 register 'liquid', LiquidTemplate
8752db2 Ryan Tomayko Add RDiscountTemplate
authored
610
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
611
2f2aa38 Ryan Tomayko :smart and :filter_html options for RDiscountTemplate
authored
612 # Discount Markdown implementation. See:
613 # http://github.com/rtomayko/rdiscount
614 #
615 # RDiscount is a simple text filter. It does not support +scope+ or
616 # +locals+. The +:smart+ and +:filter_html+ options may be set true
617 # to enable those flags on the underlying RDiscount object.
8752db2 Ryan Tomayko Add RDiscountTemplate
authored
618 class RDiscountTemplate < Template
2f2aa38 Ryan Tomayko :smart and :filter_html options for RDiscountTemplate
authored
619 def flags
620 [:smart, :filter_html].select { |flag| options[flag] }
621 end
622
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
623 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
624 return if defined? ::RDiscount
625 require_template_library 'rdiscount'
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
626 end
627
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
628 def prepare
2f2aa38 Ryan Tomayko :smart and :filter_html options for RDiscountTemplate
authored
629 @engine = RDiscount.new(data, *flags)
2ef8b6b Ryan Tomayko idempotent templates cache output on first render
authored
630 @output = nil
8752db2 Ryan Tomayko Add RDiscountTemplate
authored
631 end
632
633 def evaluate(scope, locals, &block)
2ef8b6b Ryan Tomayko idempotent templates cache output on first render
authored
634 @output ||= @engine.to_html
8752db2 Ryan Tomayko Add RDiscountTemplate
authored
635 end
636 end
637 register 'markdown', RDiscountTemplate
2f2aa38 Ryan Tomayko :smart and :filter_html options for RDiscountTemplate
authored
638 register 'mkd', RDiscountTemplate
62ffa73 Ryan Tomayko use .md in addition to .markdown for markdown templates
authored
639 register 'md', RDiscountTemplate
8752db2 Ryan Tomayko Add RDiscountTemplate
authored
640
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
641
b7a24b7 Ryan Tomayko fix strange indentation
authored
642 # RedCloth implementation. See:
643 # http://redcloth.org/
644 class RedClothTemplate < Template
645 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
646 return if defined? ::RedCloth
647 require_template_library 'redcloth'
b7a24b7 Ryan Tomayko fix strange indentation
authored
648 end
6518ccd added RedCloth
bry4n authored
649
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
650 def prepare
b7a24b7 Ryan Tomayko fix strange indentation
authored
651 @engine = RedCloth.new(data)
2ef8b6b Ryan Tomayko idempotent templates cache output on first render
authored
652 @output = nil
b7a24b7 Ryan Tomayko fix strange indentation
authored
653 end
6518ccd added RedCloth
bry4n authored
654
b7a24b7 Ryan Tomayko fix strange indentation
authored
655 def evaluate(scope, locals, &block)
2ef8b6b Ryan Tomayko idempotent templates cache output on first render
authored
656 @output ||= @engine.to_html
b7a24b7 Ryan Tomayko fix strange indentation
authored
657 end
6518ccd added RedCloth
bry4n authored
658 end
b7a24b7 Ryan Tomayko fix strange indentation
authored
659 register 'textile', RedClothTemplate
6518ccd added RedCloth
bry4n authored
660
661
36c4feb Ryan Tomayko locate mustache view classes based on filename
authored
662 # Mustache is written and maintained by Chris Wanstrath. See:
8465ac6 Dylan Egan Mustache template implementation
dylanegan authored
663 # http://github.com/defunkt/mustache
36c4feb Ryan Tomayko locate mustache view classes based on filename
authored
664 #
2a4b2c0 Ryan Tomayko add erubis, haml, and mustache docs to TEMPLATES.md
authored
665 # When a scope argument is provided to MustacheTemplate#render, the
666 # instance variables are copied from the scope object to the Mustache
667 # view.
8465ac6 Dylan Egan Mustache template implementation
dylanegan authored
668 class MustacheTemplate < Template
36c4feb Ryan Tomayko locate mustache view classes based on filename
authored
669 attr_reader :engine
670
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
671 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
672 return if defined? ::Mustache
673 require_template_library 'mustache'
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
674 end
36c4feb Ryan Tomayko locate mustache view classes based on filename
authored
675
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
676 def prepare
39d137a Chris Wanstrath Simplify Mustache template. Tests all pass but requires Mustache 0.4.0
defunkt authored
677 Mustache.view_namespace = options[:namespace]
8f16b50 Ryan Tomayko support mustache's view_path setting
authored
678 Mustache.view_path = options[:view_path] || options[:mustaches]
a19c10f Chris Wanstrath Don't need @view_name anymore - ditch it
defunkt authored
679 @engine = options[:view] || Mustache.view_class(name)
36c4feb Ryan Tomayko locate mustache view classes based on filename
authored
680 options.each do |key, value|
8f16b50 Ryan Tomayko support mustache's view_path setting
authored
681 next if %w[view view_path namespace mustaches].include?(key.to_s)
36c4feb Ryan Tomayko locate mustache view classes based on filename
authored
682 @engine.send("#{key}=", value) if @engine.respond_to? "#{key}="
683 end
8465ac6 Dylan Egan Mustache template implementation
dylanegan authored
684 end
685
36c4feb Ryan Tomayko locate mustache view classes based on filename
authored
686 def evaluate(scope=nil, locals={}, &block)
687 instance = @engine.new
688
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
689 # copy instance variables from scope to the view
36c4feb Ryan Tomayko locate mustache view classes based on filename
authored
690 scope.instance_variables.each do |name|
691 instance.instance_variable_set(name, scope.instance_variable_get(name))
692 end
693
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
694 # locals get added to the view's context
8465ac6 Dylan Egan Mustache template implementation
dylanegan authored
695 locals.each do |local, value|
36c4feb Ryan Tomayko locate mustache view classes based on filename
authored
696 instance[local] = value
8465ac6 Dylan Egan Mustache template implementation
dylanegan authored
697 end
698
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
699 # if we're passed a block it's a subview. Sticking it in yield
36c4feb Ryan Tomayko locate mustache view classes based on filename
authored
700 # lets us use {{yield}} in layout.html to render the actual page.
701 instance[:yield] = block.call if block
702
703 instance.template = data unless instance.compiled?
704
705 instance.to_html
706 end
8465ac6 Dylan Egan Mustache template implementation
dylanegan authored
707 end
708 register 'mustache', MustacheTemplate
71228c1 7rans rdoc template support
trans authored
709
3a6e53f Ryan Tomayko Merge precompiled methods into master
authored
710
71228c1 7rans rdoc template support
trans authored
711 # RDoc template. See:
712 # http://rdoc.rubyforge.org/
713 #
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
714 # It's suggested that your program require 'rdoc/markup' and
715 # 'rdoc/markup/to_html' at load time when using this template
716 # engine.
71228c1 7rans rdoc template support
trans authored
717 class RDocTemplate < Template
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
718 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
719 return if defined?(::RDoc::Markup)
720 require_template_library 'rdoc/markup'
721 require_template_library 'rdoc/markup/to_html'
54a8604 Ryan Tomayko Template#initialize_engine - called first use of template class
authored
722 end
723
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
724 def prepare
71228c1 7rans rdoc template support
trans authored
725 markup = RDoc::Markup::ToHtml.new
726 @engine = markup.convert(data)
2ef8b6b Ryan Tomayko idempotent templates cache output on first render
authored
727 @output = nil
71228c1 7rans rdoc template support
trans authored
728 end
729
730 def evaluate(scope, locals, &block)
2ef8b6b Ryan Tomayko idempotent templates cache output on first render
authored
731 @output ||= @engine.to_s
71228c1 7rans rdoc template support
trans authored
732 end
733 end
734 register 'rdoc', RDocTemplate
eecdea4 adding early coffee-script support
blahed authored
735
3a6e53f Ryan Tomayko Merge precompiled methods into master
authored
736
eecdea4 adding early coffee-script support
blahed authored
737 # CoffeeScript info:
738 # http://jashkenas.github.com/coffee-script/
739 class CoffeeTemplate < Template
740 def initialize_engine
533f8f7 Ryan Tomayko misc hygiene and style tweaks
authored
741 return if defined? ::CoffeeScript
742 require_template_library 'coffee-script'
eecdea4 adding early coffee-script support
blahed authored
743 end
744
92c64d8 Ryan Tomayko the #compile! method is now known as #prepare
authored
745 def prepare
2ef8b6b Ryan Tomayko idempotent templates cache output on first render
authored
746 @output = nil
eecdea4 adding early coffee-script support
blahed authored
747 end
748
749 def evaluate(scope, locals, &block)
2ef8b6b Ryan Tomayko idempotent templates cache output on first render
authored
750 @output ||= ::CoffeeScript::compile(data, options)
eecdea4 adding early coffee-script support
blahed authored
751 end
752 end
753 register 'coffee', CoffeeTemplate
137cd54 Ryan Tomayko Tilt!
authored
754 end
Something went wrong with that request. Please try again.