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 +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
|