sinatra-base 1.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/.yardopts +4 -0
  2. data/AUTHORS +15 -0
  3. data/CHANGES +524 -1
  4. data/Gemfile +82 -0
  5. data/LICENSE +1 -1
  6. data/README.de.rdoc +2093 -0
  7. data/README.es.rdoc +2091 -0
  8. data/README.fr.rdoc +2116 -0
  9. data/README.hu.rdoc +607 -0
  10. data/README.jp.rdoc +514 -23
  11. data/README.pt-br.rdoc +647 -0
  12. data/README.pt-pt.rdoc +646 -0
  13. data/README.rdoc +1580 -205
  14. data/README.ru.rdoc +2015 -0
  15. data/README.zh.rdoc +1816 -0
  16. data/Rakefile +110 -44
  17. data/examples/chat.rb +61 -0
  18. data/examples/simple.rb +3 -0
  19. data/examples/stream.ru +26 -0
  20. data/lib/sinatra.rb +0 -3
  21. data/lib/sinatra/base.rb +923 -393
  22. data/lib/sinatra/main.rb +9 -7
  23. data/lib/sinatra/showexceptions.rb +37 -4
  24. data/lib/sinatra/version.rb +3 -0
  25. data/sinatra-base.gemspec +15 -91
  26. data/test/base_test.rb +2 -2
  27. data/test/builder_test.rb +32 -2
  28. data/test/coffee_test.rb +92 -0
  29. data/test/contest.rb +62 -28
  30. data/test/creole_test.rb +65 -0
  31. data/test/delegator_test.rb +162 -0
  32. data/test/encoding_test.rb +20 -0
  33. data/test/erb_test.rb +25 -2
  34. data/test/extensions_test.rb +1 -1
  35. data/test/filter_test.rb +226 -8
  36. data/test/haml_test.rb +8 -2
  37. data/test/helper.rb +47 -0
  38. data/test/helpers_test.rb +1287 -80
  39. data/test/integration/app.rb +62 -0
  40. data/test/integration_helper.rb +208 -0
  41. data/test/integration_test.rb +82 -0
  42. data/test/less_test.rb +36 -6
  43. data/test/liquid_test.rb +59 -0
  44. data/test/mapped_error_test.rb +84 -7
  45. data/test/markaby_test.rb +80 -0
  46. data/test/markdown_test.rb +81 -0
  47. data/test/middleware_test.rb +1 -1
  48. data/test/nokogiri_test.rb +69 -0
  49. data/test/rack_test.rb +45 -0
  50. data/test/radius_test.rb +59 -0
  51. data/test/rdoc_test.rb +66 -0
  52. data/test/readme_test.rb +136 -0
  53. data/test/request_test.rb +13 -1
  54. data/test/response_test.rb +21 -2
  55. data/test/result_test.rb +5 -5
  56. data/test/route_added_hook_test.rb +1 -1
  57. data/test/routing_test.rb +328 -13
  58. data/test/sass_test.rb +48 -18
  59. data/test/scss_test.rb +88 -0
  60. data/test/server_test.rb +4 -3
  61. data/test/settings_test.rb +191 -21
  62. data/test/sinatra_test.rb +5 -1
  63. data/test/slim_test.rb +88 -0
  64. data/test/static_test.rb +89 -5
  65. data/test/streaming_test.rb +140 -0
  66. data/test/templates_test.rb +143 -4
  67. data/test/textile_test.rb +65 -0
  68. data/test/views/a/in_a.str +1 -0
  69. data/test/views/ascii.erb +2 -0
  70. data/test/views/b/in_b.str +1 -0
  71. data/test/views/calc.html.erb +1 -0
  72. data/test/views/explicitly_nested.str +1 -0
  73. data/test/views/hello.coffee +1 -0
  74. data/test/views/hello.creole +1 -0
  75. data/test/views/hello.liquid +1 -0
  76. data/test/views/hello.mab +1 -0
  77. data/test/views/hello.md +1 -0
  78. data/test/views/hello.nokogiri +1 -0
  79. data/test/views/hello.radius +1 -0
  80. data/test/views/hello.rdoc +1 -0
  81. data/test/views/hello.sass +1 -1
  82. data/test/views/hello.scss +3 -0
  83. data/test/views/hello.slim +1 -0
  84. data/test/views/hello.str +1 -0
  85. data/test/views/hello.textile +1 -0
  86. data/test/views/hello.yajl +1 -0
  87. data/test/views/layout2.liquid +2 -0
  88. data/test/views/layout2.mab +2 -0
  89. data/test/views/layout2.nokogiri +3 -0
  90. data/test/views/layout2.radius +2 -0
  91. data/test/views/layout2.slim +3 -0
  92. data/test/views/layout2.str +2 -0
  93. data/test/views/nested.str +1 -0
  94. data/test/views/utf8.erb +2 -0
  95. data/test/yajl_test.rb +80 -0
  96. metadata +126 -91
  97. data/lib/sinatra/tilt.rb +0 -746
  98. data/test/erubis_test.rb +0 -82
  99. data/test/views/error.erubis +0 -3
  100. data/test/views/hello.erubis +0 -1
  101. data/test/views/layout2.erubis +0 -2
@@ -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