tilt 0.3 → 0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -30,6 +30,7 @@ Support for these template engines is included with the package:
30
30
  Liquid .liquid liquid
31
31
  Mustache .mustache mustache
32
32
  RDiscount .markdown rdiscount
33
+ RedCloth .textile redcloth
33
34
 
34
35
  Basic Usage
35
36
  -----------
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
- task :default => :spec
1
+ require 'rake/testtask'
2
+ task :default => :test
2
3
 
3
4
  # SPECS =====================================================================
4
5
 
@@ -7,14 +8,10 @@ task :rcov do
7
8
  sh "rcov -Ilib:test test/*_test.rb"
8
9
  end
9
10
 
10
- desc 'Run specs with unit test style output'
11
- task :test do |t|
12
- sh 'bacon -qa'
13
- end
14
-
15
- desc 'Run specs with story style output'
16
- task :spec do |t|
17
- sh 'bacon -a'
11
+ desc 'Run tests (default)'
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.test_files = FileList['test/*_test.rb']
14
+ t.ruby_opts = ['-rubygems'] if defined? Gem
18
15
  end
19
16
 
20
17
  # PACKAGING =================================================================
@@ -1,11 +1,28 @@
1
- Templates
2
- =========
1
+ Tilt Templates
2
+ ==============
3
3
 
4
+ While all Tilt templates use the same basic interface for template loading and
5
+ evaluation, each varies in its capabilities and available options. Detailed
6
+ documentation on each supported template engine is provided below.
7
+
8
+ * [ERB](#erb) - `Tilt::ERBTemplate`
9
+ * [Erubis](#erubis) - `Tilt::ErubisTemplate`
10
+ * [Haml](#haml) - `Tilt::HamlTemplate`
11
+ * [Liquid](#liquid) - `Tilt::LiquidTemplate`
12
+ * [Mustache](#mustache) - `Tilt::MustachTemplate`
13
+
14
+ Tilt includes support for simple text formats in addition to
15
+ programmable template languages. These typically do not support
16
+ scope or locals but often support rendering options.
17
+
18
+ * [Markdown](#markdown) - `Tilt::RDiscountTemplate`
19
+ * [RDoc](#rdoc) - `Tilt::RDocTemplate`
20
+
21
+ <a name='erb'></a>
4
22
  ERB (`erb`, `rhtml`)
5
23
  --------------------
6
24
 
7
- [Docs](http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html) |
8
- [Syntax](http://vision-media.ca/resources/ruby/ruby-rdoc-documentation-syntax)
25
+ An easy to use but powerful templating system for Ruby.
9
26
 
10
27
  ### Example
11
28
 
@@ -28,9 +45,12 @@ Or, use the `Tilt::ERBTemplate` class directly to process strings:
28
45
  template = Tilt::ERBTemplate.new(nil, :trim => '<>') { "Hello <%= world %>!" }
29
46
  template.render(self, :world => 'World!')
30
47
 
48
+ __NOTE:__ It's suggested that your program `require 'erb'` at load time when
49
+ using this template engine within a threaded environment.
50
+
31
51
  ### Options
32
52
 
33
- `:trim => '-'`
53
+ #### `:trim => '-'`
34
54
 
35
55
  The ERB trim mode flags. This is a string consisting
36
56
  of any combination of the following characters:
@@ -40,10 +60,351 @@ of any combination of the following characters:
40
60
  * `'-'` omits newlines for lines ending in `-%>`.
41
61
  * `'%'` enables processing of lines beginning with `%`
42
62
 
43
- `:safe => nil`
63
+ #### `:safe => nil`
44
64
 
45
65
  The `$SAFE` level; when set, ERB code will be run in a
46
66
  separate thread with `$SAFE` set to the provided level.
47
67
 
48
- It's suggested that your program require 'erb' at load time when using this
49
- template engine.
68
+ ### See also
69
+
70
+ * [ERB documentation](http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html)
71
+
72
+
73
+ <a name='erubis'></a>
74
+ Erubis (`erubis`)
75
+ -----------------
76
+
77
+ Erubis is a fast, secure, and very extensible implementation of eRuby.
78
+
79
+ ### Usage
80
+
81
+ To use Erubis instead of ERB for all `.erb` and `.rhtml` files, register
82
+ the extensions as follows:
83
+
84
+ Tilt.register 'erb', Tilt::ErubisTemplate
85
+ Tilt.register 'rhtml', Tilt::ErubisTemplate
86
+
87
+ ### Options
88
+
89
+ #### `:trim => true`
90
+
91
+ Delete spaces around '<% %>'. (But, spaces around '<%= %>' are preserved.)
92
+
93
+ #### `:pattern => '<% %>'`
94
+
95
+ Set pattern for embedded Ruby code.
96
+
97
+ See the [ERB](#erb) template documentation for examples, usage, and options.
98
+
99
+ __NOTE:__ It's suggested that your program `require 'erubis'` at load time when
100
+ using this template engine within a threaded environment.
101
+
102
+ ### See also
103
+
104
+ * [Erubis Home](http://www.kuwata-lab.com/erubis/)
105
+ * [Erubis User's Guide](http://www.kuwata-lab.com/erubis/users-guide.html)
106
+
107
+
108
+ <a name='haml'></a>
109
+ Haml (`haml`)
110
+ -------------
111
+
112
+ Haml is a markup language that’s used to cleanly and simply describe the HTML of
113
+ any web document without the use of inline code. Haml functions as a replacement
114
+ for inline page templating systems such as PHP, ASP, and ERB, the templating
115
+ language used in most Ruby on Rails applications. However, Haml avoids the
116
+ need for explicitly coding HTML into the template, because it itself is a
117
+ description of the HTML, with some code to generate dynamic content.
118
+ ([more](http://haml-lang.com/about.html))
119
+
120
+
121
+ ### Example
122
+
123
+ %html
124
+ %head
125
+ %title= @title
126
+ %body
127
+ %h1
128
+ Hello
129
+ = world + '!'
130
+
131
+ ### Usage
132
+
133
+ The `Tilt::HamlTemplate` class is registered for all files ending in `.haml`
134
+ by default. Haml templates support custom evaluation scopes and locals:
135
+
136
+ >> require 'haml'
137
+ >> template = Tilt.new('hello.haml')
138
+ => #<Tilt::HamlTemplate @file='hello.haml'>
139
+ >> @title = "Hello Haml!"
140
+ >> template.render(self, :world => 'Haml!')
141
+ => "
142
+ <html>
143
+ <head>
144
+ <title>Hello Haml!</title>
145
+ </head>
146
+ <body>
147
+ <h1>Hello Haml!</h1>
148
+ </body>
149
+ </html>"
150
+
151
+ Or, use the `Tilt::HamlTemplate` class directly to process strings:
152
+
153
+ >> require 'haml'
154
+ >> template = Tilt::HamlTemplate.new { "%h1= 'Hello Haml!'" }
155
+ => #<Tilt::HamlTemplate @file=nil ...>
156
+ >> template.render
157
+ => "<h1>Hello Haml!</h1>"
158
+
159
+ __NOTE:__ It's suggested that your program `require 'haml'` at load time when
160
+ using this template engine within a threaded environment.
161
+
162
+ ### Options
163
+
164
+ #### `:format => :xhtml`
165
+
166
+ Determines the output format. The default is `:xhtml`. Other options are
167
+ `:html4` and `:html5`, which are identical to `:xhtml` except there are no
168
+ self-closing tags, the XML prolog is ignored and correct DOCTYPEs are generated.
169
+
170
+ #### `:escape_html => false`
171
+
172
+ Sets whether or not to escape HTML-sensitive characters in script. If this is
173
+ true, `=` behaves like `&=;` otherwise, it behaves like `!=`. Note that if this
174
+ is set, `!=` should be used for yielding to subtemplates and rendering partials.
175
+ Defaults to false.
176
+
177
+ #### `:ugly => false`
178
+
179
+ If set to true, Haml makes no attempt to properly indent or format the HTML
180
+ output. This causes the rendering to be done much quicker than it would
181
+ otherwise, but makes viewing the source unpleasant. Defaults to false.
182
+
183
+ #### `:suppress_eval => false`
184
+
185
+ Whether or not attribute hashes and Ruby scripts designated by `=` or `~` should
186
+ be evaluated. If this is true, said scripts are rendered as empty strings.
187
+ Defaults to false.
188
+
189
+ #### `:attr_wrapper => "'"`
190
+
191
+ The character that should wrap element attributes. This defaults to `'` (an
192
+ apostrophe). Characters of this type within the attributes will be escaped (e.g.
193
+ by replacing them with `&apos;`) if the character is an apostrophe or a
194
+ quotation mark.
195
+
196
+ #### `:autoclose => %w[meta img link br hr input area param col base]`
197
+
198
+ A list of tag names that should be automatically self-closed if they have no
199
+ content. Defaults to `['meta', 'img', 'link', 'br', 'hr', 'input', 'area',
200
+ 'param', 'col', 'base']`.
201
+
202
+ #### `:preserve => %w[textarea pre]`
203
+
204
+ A list of tag names that should automatically have their newlines preserved
205
+ using the `Haml::Helpers#preserve` helper. This means that any content given on
206
+ the same line as the tag will be preserved. For example, `%textarea= "Foo\nBar"`
207
+ compiles to `<textarea>Foo&#x000A;Bar</textarea>`. Defaults to `['textarea',
208
+ 'pre']`.
209
+
210
+ #### `:encoding => 'utf-8'`
211
+
212
+ The encoding to use for the HTML output. Only available in Ruby 1.9 or higher.
213
+ This can be a string or an Encoding Object. Note that Haml does not
214
+ automatically re-encode Ruby values; any strings coming from outside the
215
+ application should be converted before being passed into the Haml template.
216
+ Defaults to `Encoding.default_internal` or, if that's not set, `"utf-8"`.
217
+
218
+ ### See also
219
+
220
+ * [#haml.docs](http://haml-lang.com/docs.html)
221
+ * [Haml Tutorial](http://haml-lang.com/tutorial.html)
222
+ * [Haml Reference](http://haml-lang.com/docs/yardoc/HAML_REFERENCE.md.html)
223
+ * [Whitespace Preservation](http://haml-lang.com/docs/yardoc/HAML_REFERENCE.md.html#whitespace_preservation)
224
+
225
+
226
+ <a name='liquid'></a>
227
+ Liquid (`liquid`)
228
+ -----------------
229
+
230
+ Liquid is for rendering safe templates which cannot affect the security
231
+ of the server they are rendered on.
232
+
233
+ ### Example
234
+
235
+ <html>
236
+ <head>
237
+ <title>{{ title }}</title>
238
+ </head>
239
+ <body>
240
+ <h1>Hello {{ world }}!</h1>
241
+ </body>
242
+ </html>
243
+
244
+ ### Usage
245
+
246
+ `Tilt::LiquidTemplate` is registered for all files ending in `.liquid` by
247
+ default. Liquid templates support locals and objects that respond to
248
+ `#to_h` as scopes:
249
+
250
+ >> require 'liquid'
251
+ >> require 'tilt'
252
+ >> template = Tilt.new('hello.liquid')
253
+ => #<Tilt::LiquidTemplate @file='hello.liquid'>
254
+ >> scope = { :title => "Hello Liquid Templates" }
255
+ >> template.render(nil, :world => "Liquid")
256
+ => "
257
+ <html>
258
+ <head>
259
+ <title>Hello Liquid Templates</title>
260
+ </head>
261
+ <body>
262
+ <h1>Hello Liquid!</h1>
263
+ </body>
264
+ </html>"
265
+
266
+ Or, use `Tilt::LiquidTemplate` directly to process strings:
267
+
268
+ >> require 'haml'
269
+ >> template = Tilt::HamlTemplate.new { "<h1>Hello Liquid!</h1>" }
270
+ => #<Tilt::LiquidTemplate @file=nil ...>
271
+ >> template.render
272
+ => "<h1>Hello Liquid!</h1>"
273
+
274
+ __NOTE:__ It's suggested that your program `require 'liquid'` at load
275
+ time when using this template engine within a threaded environment.
276
+
277
+ ### See also
278
+
279
+ * [Liquid for Programmers](http://wiki.github.com/tobi/liquid/liquid-for-programmers)
280
+ * [Liquid Docs](http://liquid.rubyforge.org/)
281
+ * GitHub: [tobi/liquid](http://github.com/tobi/liquid/)
282
+
283
+ <a name='mustache'></a>
284
+ Mustache (`mustache`)
285
+ ---------------------
286
+
287
+ Mustache is a framework-agnostic way to render logic-free views.
288
+
289
+ __NOTE:__ It's suggested that your program `require 'mustache'` at load time
290
+ when using this template engine in a threaded environment.
291
+
292
+ ### Options
293
+
294
+ #### `:path => Dir.pwd`
295
+
296
+ The base path where mustache templates (`.html` files) are located. Defaults to
297
+ the current working directory.
298
+
299
+ #### `:template_extension => 'html'`
300
+
301
+ The file extension used on mustache templates. Default is `'html'`.
302
+
303
+ #### `:namespace => Object`
304
+
305
+ The class or module where View classes are located. If you have
306
+ `Hurl::App::Views`, namespace should be `Hurl:App`. This defaults to `Object`,
307
+ causing `::Views` to be searched for classes.
308
+
309
+ #### `:mustaches => nil`
310
+
311
+ Where mustache views (.rb files) are located, or nil to disable auto-requiring
312
+ of views based on template names. By default, the view file is assumed to be in
313
+ the same directory as the template file.
314
+
315
+ All other options are assumed to be attribute writer's on the Mustache
316
+ class and are set when a template is compiled. They are:
317
+
318
+ #### `:view => nil`
319
+
320
+ The Mustache subclass that should be used a the view. When this option is
321
+ specified, the template file will be determined from the view class, and the
322
+ `:namespace` and `:mustaches` options are irrelevant.
323
+
324
+ ### See also
325
+
326
+ * [Mustache Docs](http://defunkt.github.com/mustache/)
327
+ * GitHub: [defunkt/mustache](http://github.com/defunkt/mustache)
328
+
329
+
330
+ <a name='markdown'></a>
331
+ Markdown (`markdown`, `md`, `mkd`)
332
+ ----------------------------------
333
+
334
+ Markdown is a lightweight markup language, created by John Gruber and
335
+ Aaron Swartz. For any markup that is not covered by Markdown’s syntax,
336
+ HTML is used. Marking up plain text with Markdown markup is easy and
337
+ Markdown formatted texts are readable.
338
+
339
+ Markdown formatted texts are converted to HTML with the [RDiscount][]
340
+ engine, which is a Ruby extension over the fast [Discount][] C library.
341
+
342
+ ### Example
343
+
344
+ Hello Markdown Templates
345
+ ========================
346
+
347
+ Hello World. This is a paragraph.
348
+
349
+ ### Usage
350
+
351
+ To wrap a Markdown formatted document with a layout:
352
+
353
+ require 'erubis'
354
+ require 'rdiscount'
355
+ layout = Tilt::ErubisTemplate.new(nil, :pattern => '\{% %\}') do
356
+ "<!doctype html><title></title>{%= yield %}"
357
+ end
358
+ data = Tilt::RDiscountTemplate.new { "# hello tilt" }
359
+ layout.render { data.render }
360
+ # => "<!doctype html><title></title><h1>hello tilt</h1>\n"
361
+
362
+ __NOTE:__ It's suggested that your program `require 'mustache'` at load time
363
+ when using this template engine in a threaded environment.
364
+
365
+ ### Options
366
+
367
+ RDiscount supports a variety of flags that control its behavior:
368
+
369
+ #### `:smart => true|false`
370
+
371
+ Set `true` to enable [Smarty Pants](http://daringfireball.net/projects/smartypants/)
372
+ style punctuation replacement.
373
+
374
+ #### `:filter_html => true|false`
375
+
376
+ Set `true` disallow raw HTML in Markdown contents. HTML is converted to
377
+ literal text by escaping `<` characters.
378
+
379
+ ### See also
380
+
381
+ * [Markdown Syntax Documentation][markdown syntax]
382
+ * GitHub: [rtomayko/rdiscount][rdiscount]
383
+
384
+ [discount]: http://www.pell.portland.or.us/~orc/Code/discount/ "Discount"
385
+ [rdiscount]: http://github.com/rtomayko/rdiscount/ "RDiscount"
386
+ [markdown syntax]: (http://daringfireball.net/projects/markdown/syntax/) "Markdown Syntax"
387
+
388
+
389
+ <a name='rdoc'></a>
390
+ RDoc (`rdoc`)
391
+ -------------
392
+
393
+ RDoc is the simple text markup system that comes with Ruby's standard
394
+ library.
395
+
396
+ ### Usage
397
+
398
+ __NOTE:__ It's suggested that your program `require 'rdoc/markup'` and
399
+ `require 'rdoc/markup/to_html'` at load time when using this template
400
+ engine in a threaded environment.
401
+
402
+ ### Example
403
+
404
+ = Hello RDoc Templates
405
+
406
+ Hello World. This is a paragraph.
407
+
408
+ ### See also
409
+
410
+ * [RDoc](http://rdoc.sourceforge.net/doc/index.html)
@@ -1,5 +1,5 @@
1
1
  module Tilt
2
- VERSION = '0.3'
2
+ VERSION = '0.4'
3
3
 
4
4
  @template_mappings = {}
5
5
 
@@ -44,6 +44,7 @@ module Tilt
44
44
  end
45
45
  end
46
46
 
47
+
47
48
  # Base class for template implementations. Subclasses must implement
48
49
  # the #compile! method and one of the #evaluate or #template_source
49
50
  # methods.
@@ -66,6 +67,9 @@ module Tilt
66
67
  # default, template data is read from the file specified. When a block
67
68
  # is given, it should read template data and return as a String. When
68
69
  # file is nil, a block is required.
70
+ #
71
+ # The #initialize_engine method is called if this is the very first
72
+ # time this template subclass has been initialized.
69
73
  def initialize(file=nil, line=1, options={}, &block)
70
74
  raise ArgumentError, "file or block required" if file.nil? && block.nil?
71
75
  options, line = line, 1 if line.is_a?(Hash)
@@ -73,7 +77,21 @@ module Tilt
73
77
  @line = line || 1
74
78
  @options = options || {}
75
79
  @reader = block || lambda { |t| File.read(file) }
80
+
81
+ if !self.class.engine_initialized
82
+ initialize_engine
83
+ self.class.engine_initialized = true
84
+ end
85
+ end
86
+
87
+ # Called once and only once for each template subclass the first time
88
+ # the template class is initialized. This should be used to require the
89
+ # underlying template library and perform any initial setup.
90
+ def initialize_engine
76
91
  end
92
+ @engine_initialized = false
93
+ class << self ; attr_accessor :engine_initialized ; end
94
+
77
95
 
78
96
  # Load template source and compile the template. The template is
79
97
  # loaded and compiled the first time this method is called; subsequent
@@ -149,14 +167,19 @@ module Tilt
149
167
  end
150
168
  end
151
169
 
152
- # Extremely simple template cache implementation.
170
+ # Extremely simple template cache implementation. Calling applications
171
+ # create a Tilt::Cache instance and use #fetch with any set of hashable
172
+ # arguments (such as those to Tilt.new):
173
+ # cache = Tilt::Cache.new
174
+ # cache.fetch(path, line, options) { Tilt.new(path, line, options) }
175
+ #
176
+ # Subsequent invocations return the already compiled template object.
153
177
  class Cache
154
178
  def initialize
155
179
  @cache = {}
156
180
  end
157
181
 
158
182
  def fetch(*key)
159
- key = key.map { |part| part.to_s }.join(":")
160
183
  @cache[key] ||= yield
161
184
  end
162
185
 
@@ -165,8 +188,10 @@ module Tilt
165
188
  end
166
189
  end
167
190
 
191
+
168
192
  # Template Implementations ================================================
169
193
 
194
+
170
195
  # The template source is evaluated as a Ruby string. The #{} interpolation
171
196
  # syntax can be used to generated dynamic output.
172
197
  class StringTemplate < Template
@@ -180,14 +205,15 @@ module Tilt
180
205
  end
181
206
  register 'str', StringTemplate
182
207
 
208
+
183
209
  # ERB template implementation. See:
184
210
  # http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html
185
- #
186
- # It's suggested that your program require 'erb' at load
187
- # time when using this template engine.
188
211
  class ERBTemplate < Template
212
+ def initialize_engine
213
+ require_template_library 'erb' unless defined? ::ERB
214
+ end
215
+
189
216
  def compile!
190
- require_template_library 'erb' unless defined?(::ERB)
191
217
  @engine = ::ERB.new(data, options[:safe], options[:trim], '@_out_buf')
192
218
  end
193
219
 
@@ -224,28 +250,41 @@ module Tilt
224
250
  end
225
251
  %w[erb rhtml].each { |ext| register ext, ERBTemplate }
226
252
 
253
+
227
254
  # Erubis template implementation. See:
228
255
  # http://www.kuwata-lab.com/erubis/
229
- #
230
- # It's suggested that your program require 'erubis' at load
231
- # time when using this template engine.
232
256
  class ErubisTemplate < ERBTemplate
257
+ def initialize_engine
258
+ require_template_library 'erubis' unless defined? ::Erubis
259
+ end
260
+
233
261
  def compile!
234
- require_template_library 'erubis' unless defined?(::Erubis)
235
262
  Erubis::Eruby.class_eval(%Q{def add_preamble(src) src << "@_out_buf = _buf = '';" end})
236
- @engine = ::Erubis::Eruby.new(data)
263
+ @engine = ::Erubis::Eruby.new(data, options)
264
+ end
265
+
266
+ private
267
+
268
+ # Erubis doesn't have ERB's line-off-by-one under 1.9 problem. Override
269
+ # and adjust back.
270
+ if RUBY_VERSION >= '1.9.0'
271
+ def local_assignment_code(locals)
272
+ source, offset = super
273
+ [source, offset - 1]
274
+ end
237
275
  end
238
276
  end
239
277
  register 'erubis', ErubisTemplate
240
278
 
279
+
241
280
  # Haml template implementation. See:
242
281
  # http://haml.hamptoncatlin.com/
243
- #
244
- # It's suggested that your program require 'haml' at load
245
- # time when using this template engine.
246
282
  class HamlTemplate < Template
283
+ def initialize_engine
284
+ require_template_library 'haml' unless defined? ::Haml::Engine
285
+ end
286
+
247
287
  def compile!
248
- require_template_library 'haml' unless defined?(::Haml::Engine)
249
288
  @engine = ::Haml::Engine.new(data, haml_options)
250
289
  end
251
290
 
@@ -260,16 +299,17 @@ module Tilt
260
299
  end
261
300
  register 'haml', HamlTemplate
262
301
 
302
+
263
303
  # Sass template implementation. See:
264
304
  # http://haml.hamptoncatlin.com/
265
305
  #
266
306
  # Sass templates do not support object scopes, locals, or yield.
267
- #
268
- # It's suggested that your program require 'sass' at load
269
- # time when using this template engine.
270
307
  class SassTemplate < Template
308
+ def initialize_engine
309
+ require_template_library 'sass' unless defined? ::Sass::Engine
310
+ end
311
+
271
312
  def compile!
272
- require_template_library 'sass' unless defined?(::Sass::Engine)
273
313
  @engine = ::Sass::Engine.new(data, sass_options)
274
314
  end
275
315
 
@@ -284,16 +324,17 @@ module Tilt
284
324
  end
285
325
  register 'sass', SassTemplate
286
326
 
327
+
287
328
  # Builder template implementation. See:
288
329
  # http://builder.rubyforge.org/
289
- #
290
- # It's suggested that your program require 'builder' at load
291
- # time when using this template engine.
292
330
  class BuilderTemplate < Template
293
- def compile!
331
+ def initialize_engine
294
332
  require_template_library 'builder' unless defined?(::Builder)
295
333
  end
296
334
 
335
+ def compile!
336
+ end
337
+
297
338
  def evaluate(scope, locals, &block)
298
339
  xml = ::Builder::XmlMarkup.new(:indent => 2)
299
340
  if data.respond_to?(:to_str)
@@ -311,31 +352,61 @@ module Tilt
311
352
  end
312
353
  register 'builder', BuilderTemplate
313
354
 
355
+
314
356
  # Liquid template implementation. See:
315
357
  # http://liquid.rubyforge.org/
316
358
  #
317
- # LiquidTemplate does not support scopes or yield blocks.
359
+ # Liquid is designed to be a *safe* template system and threfore
360
+ # does not provide direct access to execuatable scopes. In order to
361
+ # support a +scope+, the +scope+ must be able to represent itself
362
+ # as a hash by responding to #to_h. If the +scope+ does not respond
363
+ # to #to_h it will be ignored.
364
+ #
365
+ # LiquidTemplate does not support yield blocks.
318
366
  #
319
367
  # It's suggested that your program require 'liquid' at load
320
368
  # time when using this template engine.
321
369
  class LiquidTemplate < Template
370
+ def initialize_engine
371
+ require_template_library 'liquid' unless defined? ::Liquid::Template
372
+ end
373
+
322
374
  def compile!
323
- require_template_library 'liquid' unless defined?(::Liquid::Template)
324
375
  @engine = ::Liquid::Template.parse(data)
325
376
  end
326
377
 
327
378
  def evaluate(scope, locals, &block)
328
- locals = locals.inject({}) { |hash,(k,v)| hash[k.to_s] = v ; hash }
379
+ locals = locals.inject({}){ |h,(k,v)| h[k.to_s] = v ; h }
380
+ if scope.respond_to?(:to_h)
381
+ scope = scope.to_h.inject({}){ |h,(k,v)| h[k.to_s] = v ; h }
382
+ locals = scope.merge(locals)
383
+ end
384
+ # TODO: Is it possible to lazy yield ?
385
+ locals['yield'] = block.nil? ? '' : yield
386
+ locals['content'] = block.nil? ? '' : yield
329
387
  @engine.render(locals)
330
388
  end
331
389
  end
332
390
  register 'liquid', LiquidTemplate
333
391
 
334
- # Discount Markdown implementation.
392
+
393
+ # Discount Markdown implementation. See:
394
+ # http://github.com/rtomayko/rdiscount
395
+ #
396
+ # RDiscount is a simple text filter. It does not support +scope+ or
397
+ # +locals+. The +:smart+ and +:filter_html+ options may be set true
398
+ # to enable those flags on the underlying RDiscount object.
335
399
  class RDiscountTemplate < Template
400
+ def flags
401
+ [:smart, :filter_html].select { |flag| options[flag] }
402
+ end
403
+
404
+ def initialize_engine
405
+ require_template_library 'rdiscount' unless defined? ::RDiscount
406
+ end
407
+
336
408
  def compile!
337
- require_template_library 'rdiscount' unless defined?(::RDiscount)
338
- @engine = RDiscount.new(data)
409
+ @engine = RDiscount.new(data, *flags)
339
410
  end
340
411
 
341
412
  def evaluate(scope, locals, &block)
@@ -343,66 +414,44 @@ module Tilt
343
414
  end
344
415
  end
345
416
  register 'markdown', RDiscountTemplate
417
+ register 'mkd', RDiscountTemplate
346
418
  register 'md', RDiscountTemplate
347
419
 
420
+
421
+ # RedCloth implementation. See:
422
+ # http://redcloth.org/
423
+ class RedClothTemplate < Template
424
+ def initialize_engine
425
+ require_template_library 'redcloth' unless defined? ::RedCloth
426
+ end
427
+
428
+ def compile!
429
+ @engine = RedCloth.new(data)
430
+ end
431
+
432
+ def evaluate(scope, locals, &block)
433
+ @engine.to_html
434
+ end
435
+ end
436
+ register 'textile', RedClothTemplate
437
+
438
+
348
439
  # Mustache is written and maintained by Chris Wanstrath. See:
349
440
  # http://github.com/defunkt/mustache
350
441
  #
351
- # It's suggested that your program require 'mustache' at load
352
- # time when using this template engine.
353
- #
354
- # Mustache templates support the following options:
355
- #
356
- # * :view - The Mustache subclass that should be used a the view. When
357
- # this option is specified, the template file will be determined from
358
- # the view class, and the :namespace and :mustaches options are
359
- # irrelevant.
360
- #
361
- # * :namespace - The class or module where View classes are located.
362
- # If you have Hurl::App::Views, namespace should be Hurl:App. This
363
- # defaults to Object, causing ::Views to be searched for classes.
364
- #
365
- # * :mustaches - Where mustache views (.rb files) are located, or nil
366
- # disable auto-requiring of views based on template names. By default,
367
- # the view file is assumed to be in the same directory as the template
368
- # file.
369
- #
370
- # All other options are assumed to be attribute writer's on the Mustache
371
- # class and are set when a template is compiled. They are:
372
- #
373
- # * :path - The base path where mustache templates (.html files) are
374
- # located. This defaults to the current working directory.
375
- #
376
- # * :template_extension - The file extension used on mustache templates.
377
- # The default is 'html'.
378
- #
442
+ # When a scope argument is provided to MustacheTemplate#render, the
443
+ # instance variables are copied from the scope object to the Mustache
444
+ # view.
379
445
  class MustacheTemplate < Template
380
446
  attr_reader :engine
381
447
 
382
- # Locates and compiles the Mustache object used to create new views. The
383
- def compile!
384
- require_template_library 'mustache' unless defined?(::Mustache)
385
-
386
- @view_name = Mustache.classify(name.to_s)
387
- @namespace = options[:namespace] || Object
388
-
389
- # Figure out which Mustache class to use.
390
- @engine =
391
- if options[:view]
392
- @view_name = options[:view].name
393
- options[:view]
394
- elsif @namespace.const_defined?(:Views) &&
395
- @namespace::Views.const_defined?(@view_name)
396
- @namespace::Views.const_get(@view_name)
397
- elsif load_mustache_view
398
- engine = @namespace::Views.const_get(@view_name)
399
- engine.template = data
400
- engine
401
- else
402
- Mustache
403
- end
448
+ def initialize_engine
449
+ require_template_library 'mustache' unless defined? ::Mustache
450
+ end
404
451
 
405
- # set options on the view class
452
+ def compile!
453
+ Mustache.view_namespace = options[:namespace]
454
+ @engine = options[:view] || Mustache.view_class(name)
406
455
  options.each do |key, value|
407
456
  next if %w[view namespace mustaches].include?(key.to_s)
408
457
  @engine.send("#{key}=", value) if @engine.respond_to? "#{key}="
@@ -410,20 +459,19 @@ module Tilt
410
459
  end
411
460
 
412
461
  def evaluate(scope=nil, locals={}, &block)
413
- # Create a new instance for playing with
414
462
  instance = @engine.new
415
463
 
416
- # Copy instance variables from scope to the view
464
+ # copy instance variables from scope to the view
417
465
  scope.instance_variables.each do |name|
418
466
  instance.instance_variable_set(name, scope.instance_variable_get(name))
419
467
  end
420
468
 
421
- # Locals get added to the view's context
469
+ # locals get added to the view's context
422
470
  locals.each do |local, value|
423
471
  instance[local] = value
424
472
  end
425
473
 
426
- # If we're passed a block it's a subview. Sticking it in yield
474
+ # if we're passed a block it's a subview. Sticking it in yield
427
475
  # lets us use {{yield}} in layout.html to render the actual page.
428
476
  instance[:yield] = block.call if block
429
477
 
@@ -431,19 +479,31 @@ module Tilt
431
479
 
432
480
  instance.to_html
433
481
  end
482
+ end
483
+ register 'mustache', MustacheTemplate
434
484
 
435
- # Require the mustache view lib if it exists.
436
- def load_mustache_view
437
- return if name.nil?
438
- path = "#{options[:mustaches]}/#{name}.rb"
439
- if options[:mustaches] && File.exist?(path)
440
- require path.chomp('.rb')
441
- path
442
- elsif File.exist?(path = file.sub(/\.[^\/]+$/, '.rb'))
443
- require path.chomp('.rb')
444
- path
485
+ # RDoc template. See:
486
+ # http://rdoc.rubyforge.org/
487
+ #
488
+ # It's suggested that your program require 'rdoc/markup' and
489
+ # 'rdoc/markup/to_html' at load time when using this template
490
+ # engine.
491
+ class RDocTemplate < Template
492
+ def initialize_engine
493
+ unless defined?(::RDoc::Markup)
494
+ require_template_library 'rdoc/markup'
495
+ require_template_library 'rdoc/markup/to_html'
445
496
  end
446
497
  end
498
+
499
+ def compile!
500
+ markup = RDoc::Markup::ToHtml.new
501
+ @engine = markup.convert(data)
502
+ end
503
+
504
+ def evaluate(scope, locals, &block)
505
+ @engine.to_s
506
+ end
447
507
  end
448
- register 'mustache', MustacheTemplate
508
+ register 'rdoc', RDocTemplate
449
509
  end