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