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 +1 -0
- data/Rakefile +6 -9
- data/TEMPLATES.md +369 -8
- data/lib/tilt.rb +156 -96
- data/test/tilt_buildertemplate_test.rb +44 -0
- data/test/tilt_cache_test.rb +33 -0
- data/test/tilt_erbtemplate_test.rb +93 -0
- data/test/tilt_erubistemplate_test.rb +85 -0
- data/test/{spec_tilt_hamltemplate.rb → tilt_hamltemplate_test.rb} +20 -20
- data/test/tilt_liquidtemplate_test.rb +73 -0
- data/test/{spec_tilt_mustachetemplate.rb → tilt_mustachetemplate_test.rb} +23 -23
- data/test/tilt_rdiscounttemplate_test.rb +40 -0
- data/test/tilt_rdoctemplate_test.rb +19 -0
- data/test/tilt_redclothtemplate_test.rb +20 -0
- data/test/tilt_sasstemplate_test.rb +21 -0
- data/test/{spec_tilt_stringtemplate.rb → tilt_stringtemplate_test.rb} +24 -24
- data/test/tilt_template_test.rb +136 -0
- data/test/tilt_test.rb +57 -0
- data/tilt.gemspec +23 -14
- metadata +90 -29
- data/test/.bacon +0 -0
- data/test/spec_tilt.rb +0 -53
- data/test/spec_tilt_buildertemplate.rb +0 -41
- data/test/spec_tilt_erbtemplate.rb +0 -93
- data/test/spec_tilt_erubistemplate.rb +0 -78
- data/test/spec_tilt_liquid_template.rb +0 -25
- data/test/spec_tilt_rdiscount.rb +0 -19
- data/test/spec_tilt_sasstemplate.rb +0 -21
- data/test/spec_tilt_template.rb +0 -110
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
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
|
11
|
-
|
12
|
-
|
13
|
-
|
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 =================================================================
|
data/TEMPLATES.md
CHANGED
@@ -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
|
-
|
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
|
-
|
49
|
-
|
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 `'`) 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
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)
|
data/lib/tilt.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Tilt
|
2
|
-
VERSION = '0.
|
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
|
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
|
-
#
|
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({})
|
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
|
-
|
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
|
-
|
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
|
-
#
|
352
|
-
#
|
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
|
-
|
383
|
-
|
384
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
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 '
|
508
|
+
register 'rdoc', RDocTemplate
|
449
509
|
end
|