tilt 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
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