tilt 1.4.1 → 2.0.0.beta1
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +33 -26
- data/README.md +21 -48
- data/Rakefile +21 -30
- data/{TEMPLATES.md → docs/TEMPLATES.md} +10 -4
- data/docs/common.css +14 -0
- data/lib/tilt.rb +85 -154
- data/lib/tilt/asciidoc.rb +1 -8
- data/lib/tilt/bluecloth.rb +24 -0
- data/lib/tilt/builder.rb +1 -8
- data/lib/tilt/coffee.rb +1 -8
- data/lib/tilt/creole.rb +25 -0
- data/lib/tilt/csv.rb +7 -13
- data/lib/tilt/erb.rb +2 -55
- data/lib/tilt/erubis.rb +43 -0
- data/lib/tilt/haml.rb +1 -8
- data/lib/tilt/kramdown.rb +33 -0
- data/lib/tilt/less.rb +38 -0
- data/lib/tilt/liquid.rb +1 -8
- data/lib/tilt/mapping.rb +247 -0
- data/lib/tilt/markaby.rb +1 -8
- data/lib/tilt/maruku.rb +22 -0
- data/lib/tilt/nokogiri.rb +1 -8
- data/lib/tilt/radius.rb +1 -8
- data/lib/tilt/rdiscount.rb +39 -0
- data/lib/tilt/rdoc.rb +3 -10
- data/lib/tilt/redcarpet.rb +104 -0
- data/lib/tilt/{textile.rb → redcloth.rb} +1 -8
- data/lib/tilt/sass.rb +41 -0
- data/lib/tilt/template.rb +85 -92
- data/lib/tilt/wikicloth.rb +22 -0
- data/lib/tilt/yajl.rb +1 -8
- data/test/{contest.rb → test_helper.rb} +5 -11
- data/test/tilt_asciidoctor_test.rb +6 -6
- data/test/tilt_blueclothtemplate_test.rb +3 -15
- data/test/tilt_buildertemplate_test.rb +3 -3
- data/test/tilt_cache_test.rb +2 -2
- data/test/tilt_coffeescripttemplate_test.rb +8 -18
- data/test/tilt_compilesite_test.rb +2 -2
- data/test/tilt_creoletemplate_test.rb +3 -7
- data/test/tilt_csv_test.rb +5 -9
- data/test/tilt_erbtemplate_test.rb +7 -7
- data/test/tilt_erubistemplate_test.rb +7 -7
- data/test/tilt_etannitemplate_test.rb +4 -3
- data/test/tilt_hamltemplate_test.rb +4 -4
- data/test/tilt_kramdown_test.rb +5 -27
- data/test/tilt_lesstemplate_test.rb +3 -3
- data/test/tilt_liquidtemplate_test.rb +3 -3
- data/test/tilt_mapping.rb +215 -0
- data/test/tilt_markaby_test.rb +4 -4
- data/test/tilt_markdown_test.rb +13 -14
- data/test/tilt_marukutemplate_test.rb +6 -18
- data/test/tilt_metadata_test.rb +42 -0
- data/test/tilt_nokogiritemplate_test.rb +3 -3
- data/test/tilt_radiustemplate_test.rb +3 -3
- data/test/tilt_rdiscounttemplate_test.rb +6 -18
- data/test/tilt_rdoctemplate_test.rb +3 -5
- data/test/tilt_redcarpettemplate_test.rb +11 -23
- data/test/tilt_redclothtemplate_test.rb +3 -3
- data/test/tilt_sasstemplate_test.rb +4 -4
- data/test/tilt_stringtemplate_test.rb +4 -3
- data/test/tilt_template_test.rb +35 -49
- data/test/tilt_test.rb +10 -15
- data/test/tilt_wikiclothtemplate_test.rb +3 -3
- data/test/tilt_yajltemplate_test.rb +3 -3
- data/tilt.gemspec +19 -32
- metadata +26 -386
- data/lib/tilt/css.rb +0 -80
- data/lib/tilt/markdown.rb +0 -214
- data/lib/tilt/wiki.rb +0 -58
- data/test/tilt_fallback_test.rb +0 -122
data/lib/tilt/markaby.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'tilt/template'
|
2
|
+
require 'markaby'
|
2
3
|
|
3
4
|
module Tilt
|
4
5
|
# Markaby
|
@@ -14,14 +15,6 @@ module Tilt
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
|
-
def self.engine_initialized?
|
18
|
-
defined? ::Markaby
|
19
|
-
end
|
20
|
-
|
21
|
-
def initialize_engine
|
22
|
-
require_template_library 'markaby'
|
23
|
-
end
|
24
|
-
|
25
18
|
def prepare
|
26
19
|
end
|
27
20
|
|
data/lib/tilt/maruku.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
require 'maruku'
|
3
|
+
|
4
|
+
module Tilt
|
5
|
+
# Maruku markdown implementation. See:
|
6
|
+
# http://maruku.rubyforge.org/
|
7
|
+
class MarukuTemplate < Template
|
8
|
+
def prepare
|
9
|
+
@engine = Maruku.new(data, options)
|
10
|
+
@output = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluate(scope, locals, &block)
|
14
|
+
@output ||= @engine.to_html
|
15
|
+
end
|
16
|
+
|
17
|
+
def allows_script?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
data/lib/tilt/nokogiri.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'tilt/template'
|
2
|
+
require 'nokogiri'
|
2
3
|
|
3
4
|
module Tilt
|
4
5
|
# Nokogiri template implementation. See:
|
@@ -7,14 +8,6 @@ module Tilt
|
|
7
8
|
DOCUMENT_HEADER = /^<\?xml version=\"1\.0\"\?>\n?/
|
8
9
|
self.default_mime_type = 'text/xml'
|
9
10
|
|
10
|
-
def self.engine_initialized?
|
11
|
-
defined? ::Nokogiri
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize_engine
|
15
|
-
require_template_library 'nokogiri'
|
16
|
-
end
|
17
|
-
|
18
11
|
def prepare; end
|
19
12
|
|
20
13
|
def evaluate(scope, locals)
|
data/lib/tilt/radius.rb
CHANGED
@@ -1,13 +1,10 @@
|
|
1
1
|
require 'tilt/template'
|
2
|
+
require 'radius'
|
2
3
|
|
3
4
|
module Tilt
|
4
5
|
# Radius Template
|
5
6
|
# http://github.com/jlong/radius/
|
6
7
|
class RadiusTemplate < Template
|
7
|
-
def self.engine_initialized?
|
8
|
-
defined? ::Radius
|
9
|
-
end
|
10
|
-
|
11
8
|
def self.context_class
|
12
9
|
@context_class ||= Class.new(Radius::Context) do
|
13
10
|
attr_accessor :tilt_scope
|
@@ -24,10 +21,6 @@ module Tilt
|
|
24
21
|
end
|
25
22
|
end
|
26
23
|
|
27
|
-
def initialize_engine
|
28
|
-
require_template_library 'radius'
|
29
|
-
end
|
30
|
-
|
31
24
|
def prepare
|
32
25
|
end
|
33
26
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
require 'rdiscount'
|
3
|
+
|
4
|
+
module Tilt
|
5
|
+
# Discount Markdown implementation. See:
|
6
|
+
# http://github.com/rtomayko/rdiscount
|
7
|
+
#
|
8
|
+
# RDiscount is a simple text filter. It does not support +scope+ or
|
9
|
+
# +locals+. The +:smart+ and +:filter_html+ options may be set true
|
10
|
+
# to enable those flags on the underlying RDiscount object.
|
11
|
+
class RDiscountTemplate < Template
|
12
|
+
self.default_mime_type = 'text/html'
|
13
|
+
|
14
|
+
ALIAS = {
|
15
|
+
:escape_html => :filter_html,
|
16
|
+
:smartypants => :smart
|
17
|
+
}
|
18
|
+
|
19
|
+
FLAGS = [:smart, :filter_html, :smartypants, :escape_html]
|
20
|
+
|
21
|
+
def flags
|
22
|
+
FLAGS.select { |flag| options[flag] }.map { |flag| ALIAS[flag] || flag }
|
23
|
+
end
|
24
|
+
|
25
|
+
def prepare
|
26
|
+
@engine = RDiscount.new(data, *flags)
|
27
|
+
@output = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def evaluate(scope, locals, &block)
|
31
|
+
@output ||= @engine.to_html
|
32
|
+
end
|
33
|
+
|
34
|
+
def allows_script?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
data/lib/tilt/rdoc.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
require 'tilt/template'
|
2
|
+
require 'rdoc'
|
3
|
+
require 'rdoc/markup'
|
4
|
+
require 'rdoc/markup/to_html'
|
2
5
|
|
3
6
|
module Tilt
|
4
7
|
# RDoc template. See:
|
@@ -10,16 +13,6 @@ module Tilt
|
|
10
13
|
class RDocTemplate < Template
|
11
14
|
self.default_mime_type = 'text/html'
|
12
15
|
|
13
|
-
def self.engine_initialized?
|
14
|
-
defined? ::RDoc::Markup::ToHtml
|
15
|
-
end
|
16
|
-
|
17
|
-
def initialize_engine
|
18
|
-
require_template_library 'rdoc'
|
19
|
-
require_template_library 'rdoc/markup'
|
20
|
-
require_template_library 'rdoc/markup/to_html'
|
21
|
-
end
|
22
|
-
|
23
16
|
def markup
|
24
17
|
begin
|
25
18
|
# RDoc 4.0
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
require 'redcarpet'
|
3
|
+
|
4
|
+
module Tilt
|
5
|
+
# Compatibility mode for Redcarpet 1.x
|
6
|
+
class Redcarpet1Template < Template
|
7
|
+
self.default_mime_type = 'text/html'
|
8
|
+
|
9
|
+
ALIAS = {
|
10
|
+
:escape_html => :filter_html,
|
11
|
+
:smartypants => :smart
|
12
|
+
}
|
13
|
+
|
14
|
+
FLAGS = [:smart, :filter_html, :smartypants, :escape_html]
|
15
|
+
|
16
|
+
def flags
|
17
|
+
FLAGS.select { |flag| options[flag] }.map { |flag| ALIAS[flag] || flag }
|
18
|
+
end
|
19
|
+
|
20
|
+
def prepare
|
21
|
+
@engine = RedcarpetCompat.new(data, *flags)
|
22
|
+
@output = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def evaluate(scope, locals, &block)
|
26
|
+
@output ||= @engine.to_html
|
27
|
+
end
|
28
|
+
|
29
|
+
def allows_script?
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Future proof mode for Redcarpet 2.x (not yet released)
|
35
|
+
class Redcarpet2Template < Template
|
36
|
+
self.default_mime_type = 'text/html'
|
37
|
+
|
38
|
+
def self.engine_initialized?
|
39
|
+
defined? ::Redcarpet::Render and defined? ::Redcarpet::Markdown
|
40
|
+
end
|
41
|
+
|
42
|
+
def generate_renderer
|
43
|
+
renderer = options.delete(:renderer) || ::Redcarpet::Render::HTML
|
44
|
+
return renderer unless options.delete(:smartypants)
|
45
|
+
return renderer if renderer.is_a?(Class) && renderer <= ::Redcarpet::Render::SmartyPants
|
46
|
+
|
47
|
+
if renderer == ::Redcarpet::Render::XHTML
|
48
|
+
::Redcarpet::Render::SmartyHTML.new(:xhtml => true)
|
49
|
+
elsif renderer == ::Redcarpet::Render::HTML
|
50
|
+
::Redcarpet::Render::SmartyHTML
|
51
|
+
elsif renderer.is_a? Class
|
52
|
+
Class.new(renderer) { include ::Redcarpet::Render::SmartyPants }
|
53
|
+
else
|
54
|
+
renderer.extend ::Redcarpet::Render::SmartyPants
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def prepare
|
59
|
+
# try to support the same aliases
|
60
|
+
Redcarpet1Template::ALIAS.each do |opt, aka|
|
61
|
+
next if options.key? opt or not options.key? aka
|
62
|
+
options[opt] = options.delete(aka)
|
63
|
+
end
|
64
|
+
|
65
|
+
# only raise an exception if someone is trying to enable :escape_html
|
66
|
+
options.delete(:escape_html) unless options[:escape_html]
|
67
|
+
|
68
|
+
@engine = ::Redcarpet::Markdown.new(generate_renderer, options)
|
69
|
+
@output = nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def evaluate(scope, locals, &block)
|
73
|
+
@output ||= @engine.render(data)
|
74
|
+
end
|
75
|
+
|
76
|
+
def allows_script?
|
77
|
+
false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Upskirt Markdown implementation. See:
|
82
|
+
# https://github.com/tanoku/redcarpet
|
83
|
+
#
|
84
|
+
# Supports both Redcarpet 1.x and 2.x
|
85
|
+
class RedcarpetTemplate < Template
|
86
|
+
Redcarpet1 = Redcarpet1Template
|
87
|
+
Redcarpet2 = Redcarpet2Template
|
88
|
+
|
89
|
+
def prepare
|
90
|
+
klass = Redcarpet2.engine_initialized? ? Redcarpet2 : Redcarpet1
|
91
|
+
@engine = klass.new(file, line, options) { data }
|
92
|
+
end
|
93
|
+
|
94
|
+
def evaluate(scope, locals, &block)
|
95
|
+
@engine.evaluate(scope, locals, &block)
|
96
|
+
end
|
97
|
+
|
98
|
+
def allows_script?
|
99
|
+
false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
@@ -1,17 +1,10 @@
|
|
1
1
|
require 'tilt/template'
|
2
|
+
require 'redcloth'
|
2
3
|
|
3
4
|
module Tilt
|
4
5
|
# RedCloth implementation. See:
|
5
6
|
# http://redcloth.org/
|
6
7
|
class RedClothTemplate < Template
|
7
|
-
def self.engine_initialized?
|
8
|
-
defined? ::RedCloth
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize_engine
|
12
|
-
require_template_library 'redcloth'
|
13
|
-
end
|
14
|
-
|
15
8
|
def prepare
|
16
9
|
@engine = RedCloth.new(data)
|
17
10
|
options.each {|k, v| @engine.send("#{k}=", v) if @engine.respond_to? "#{k}="}
|
data/lib/tilt/sass.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
require 'sass'
|
3
|
+
|
4
|
+
module Tilt
|
5
|
+
# Sass template implementation. See:
|
6
|
+
# http://haml.hamptoncatlin.com/
|
7
|
+
#
|
8
|
+
# Sass templates do not support object scopes, locals, or yield.
|
9
|
+
class SassTemplate < Template
|
10
|
+
self.default_mime_type = 'text/css'
|
11
|
+
|
12
|
+
def prepare
|
13
|
+
@engine = ::Sass::Engine.new(data, sass_options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def evaluate(scope, locals, &block)
|
17
|
+
@output ||= @engine.render
|
18
|
+
end
|
19
|
+
|
20
|
+
def allows_script?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def sass_options
|
26
|
+
options.merge(:filename => eval_file, :line => line, :syntax => :sass)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Sass's new .scss type template implementation.
|
31
|
+
class ScssTemplate < SassTemplate
|
32
|
+
self.default_mime_type = 'text/css'
|
33
|
+
|
34
|
+
private
|
35
|
+
def sass_options
|
36
|
+
options.merge(:filename => eval_file, :line => line, :syntax => :scss)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
data/lib/tilt/template.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
require 'thread'
|
3
|
+
|
1
4
|
module Tilt
|
5
|
+
# @private
|
2
6
|
TOPOBJECT = Object.superclass || Object
|
7
|
+
# @private
|
8
|
+
LOCK = Mutex.new
|
3
9
|
|
4
10
|
# Base class for template implementations. Subclasses must implement
|
5
11
|
# the #prepare method and one of the #evaluate or #precompiled_template
|
@@ -19,14 +25,22 @@ module Tilt
|
|
19
25
|
# interface.
|
20
26
|
attr_reader :options
|
21
27
|
|
22
|
-
# Used to determine if this class's initialize_engine method has
|
23
|
-
# been called yet.
|
24
|
-
@engine_initialized = false
|
25
28
|
class << self
|
26
|
-
|
27
|
-
|
29
|
+
# An empty Hash that the template engine can populate with various
|
30
|
+
# metadata.
|
31
|
+
def metadata
|
32
|
+
@metadata ||= {}
|
33
|
+
end
|
28
34
|
|
29
|
-
|
35
|
+
# @deprecated Use `.metadata[:mime_type]` instead.
|
36
|
+
def default_mime_type
|
37
|
+
metadata[:mime_type]
|
38
|
+
end
|
39
|
+
|
40
|
+
# @deprecated Use `.metadata[:mime_type] = val` instead.
|
41
|
+
def default_mime_type=(value)
|
42
|
+
metadata[:mime_type] = value
|
43
|
+
end
|
30
44
|
end
|
31
45
|
|
32
46
|
# Create a new template with the file, line, and options specified. By
|
@@ -50,13 +64,6 @@ module Tilt
|
|
50
64
|
|
51
65
|
raise ArgumentError, "file or block required" if (@file || block).nil?
|
52
66
|
|
53
|
-
# call the initialize_engine method if this is the very first time
|
54
|
-
# an instance of this class has been created.
|
55
|
-
if !self.class.engine_initialized?
|
56
|
-
initialize_engine
|
57
|
-
self.class.engine_initialized = true
|
58
|
-
end
|
59
|
-
|
60
67
|
# used to hold compiled template methods
|
61
68
|
@compiled_method = {}
|
62
69
|
|
@@ -79,28 +86,15 @@ module Tilt
|
|
79
86
|
prepare
|
80
87
|
end
|
81
88
|
|
82
|
-
# The encoding of the source data. Defaults to the
|
83
|
-
# default_encoding-option if present. You may override this method
|
84
|
-
# in your template class if you have a better hint of the data's
|
85
|
-
# encoding.
|
86
|
-
def default_encoding
|
87
|
-
@default_encoding
|
88
|
-
end
|
89
|
-
|
90
|
-
def read_template_file
|
91
|
-
data = File.open(file, 'rb') { |io| io.read }
|
92
|
-
if data.respond_to?(:force_encoding)
|
93
|
-
# Set it to the default external (without verifying)
|
94
|
-
data.force_encoding(Encoding.default_external) if Encoding.default_external
|
95
|
-
end
|
96
|
-
data
|
97
|
-
end
|
98
|
-
|
99
89
|
# Render the template in the given scope with the locals specified. If a
|
100
90
|
# block is given, it is typically available within the template via
|
101
91
|
# +yield+.
|
102
92
|
def render(scope=Object.new, locals={}, &block)
|
103
|
-
|
93
|
+
current_template = Thread.current[:tilt_current_template]
|
94
|
+
Thread.current[:tilt_current_template] = self
|
95
|
+
evaluate(scope, locals || {}, &block)
|
96
|
+
ensure
|
97
|
+
Thread.current[:tilt_current_template] = current_template
|
104
98
|
end
|
105
99
|
|
106
100
|
# The basename of the template file.
|
@@ -118,30 +112,26 @@ module Tilt
|
|
118
112
|
file || '(__TEMPLATE__)'
|
119
113
|
end
|
120
114
|
|
121
|
-
#
|
122
|
-
#
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
115
|
+
# An empty Hash that the template engine can populate with various
|
116
|
+
# metadata.
|
117
|
+
def metadata
|
118
|
+
if respond_to?(:allows_script?)
|
119
|
+
self.class.metadata.merge(:allows_script => allows_script?)
|
120
|
+
else
|
121
|
+
self.class.metadata
|
122
|
+
end
|
128
123
|
end
|
129
124
|
|
130
|
-
|
131
|
-
# Called once and only once for each template subclass the first time
|
132
|
-
# the template class is initialized. This should be used to require the
|
133
|
-
# underlying template library and perform any initial setup.
|
134
|
-
def initialize_engine
|
135
|
-
end
|
125
|
+
protected
|
136
126
|
|
137
|
-
#
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
127
|
+
# @!group For template implementations
|
128
|
+
|
129
|
+
# The encoding of the source data. Defaults to the
|
130
|
+
# default_encoding-option if present. You may override this method
|
131
|
+
# in your template class if you have a better hint of the data's
|
132
|
+
# encoding.
|
133
|
+
def default_encoding
|
134
|
+
@default_encoding
|
145
135
|
end
|
146
136
|
|
147
137
|
# Do whatever preparation is necessary to setup the underlying template
|
@@ -150,13 +140,7 @@ module Tilt
|
|
150
140
|
#
|
151
141
|
# Subclasses must provide an implementation of this method.
|
152
142
|
def prepare
|
153
|
-
|
154
|
-
# backward compat with tilt < 0.6; just in case
|
155
|
-
warn 'Tilt::Template#compile! is deprecated; implement #prepare instead.'
|
156
|
-
compile!
|
157
|
-
else
|
158
|
-
raise NotImplementedError
|
159
|
-
end
|
143
|
+
raise NotImplementedError
|
160
144
|
end
|
161
145
|
|
162
146
|
# Execute the compiled template and return the result string. Template
|
@@ -179,10 +163,10 @@ module Tilt
|
|
179
163
|
# control over source generation or want to adjust the default line
|
180
164
|
# offset. In most cases, overriding the #precompiled_template method is
|
181
165
|
# easier and more appropriate.
|
182
|
-
def precompiled(
|
183
|
-
preamble = precompiled_preamble(
|
184
|
-
template = precompiled_template(
|
185
|
-
postamble = precompiled_postamble(
|
166
|
+
def precompiled(local_keys)
|
167
|
+
preamble = precompiled_preamble(local_keys)
|
168
|
+
template = precompiled_template(local_keys)
|
169
|
+
postamble = precompiled_postamble(local_keys)
|
186
170
|
source = ''
|
187
171
|
|
188
172
|
# Ensure that our generated source code has the same encoding as the
|
@@ -194,10 +178,7 @@ module Tilt
|
|
194
178
|
template.force_encoding(template_encoding)
|
195
179
|
end
|
196
180
|
|
197
|
-
|
198
|
-
warn "precompiled_preamble should return String (not Array)" if preamble.is_a?(Array)
|
199
|
-
warn "precompiled_postamble should return String (not Array)" if postamble.is_a?(Array)
|
200
|
-
source << [preamble, template, postamble].join("\n")
|
181
|
+
source << preamble << "\n" << template << "\n" << postamble
|
201
182
|
|
202
183
|
[source, preamble.count("\n")+1]
|
203
184
|
end
|
@@ -208,41 +189,52 @@ module Tilt
|
|
208
189
|
# the base Template guarantees correct file/line handling, locals
|
209
190
|
# support, custom scopes, proper encoding, and support for template
|
210
191
|
# compilation.
|
211
|
-
def precompiled_template(
|
192
|
+
def precompiled_template(local_keys)
|
212
193
|
raise NotImplementedError
|
213
194
|
end
|
214
195
|
|
215
|
-
|
216
|
-
|
217
|
-
# assignment only. Lines included in the preamble are subtracted from the
|
218
|
-
# source line offset, so adding code to the preamble does not effect line
|
219
|
-
# reporting in Kernel::caller and backtraces.
|
220
|
-
def precompiled_preamble(locals)
|
221
|
-
locals.map do |k,v|
|
222
|
-
if k.to_s =~ /\A[a-z_][a-zA-Z_0-9]*\z/
|
223
|
-
"#{k} = locals[#{k.inspect}]"
|
224
|
-
else
|
225
|
-
raise "invalid locals key: #{k.inspect} (keys must be variable names)"
|
226
|
-
end
|
227
|
-
end.join("\n")
|
196
|
+
def precompiled_preamble(local_keys)
|
197
|
+
''
|
228
198
|
end
|
229
199
|
|
230
|
-
|
231
|
-
# string returned from this method is appended to the precompiled
|
232
|
-
# template source.
|
233
|
-
def precompiled_postamble(locals)
|
200
|
+
def precompiled_postamble(local_keys)
|
234
201
|
''
|
235
202
|
end
|
236
203
|
|
204
|
+
# !@endgroup
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def read_template_file
|
209
|
+
data = File.open(file, 'rb') { |io| io.read }
|
210
|
+
if data.respond_to?(:force_encoding)
|
211
|
+
# Set it to the default external (without verifying)
|
212
|
+
data.force_encoding(Encoding.default_external) if Encoding.default_external
|
213
|
+
end
|
214
|
+
data
|
215
|
+
end
|
216
|
+
|
237
217
|
# The compiled method for the locals keys provided.
|
238
218
|
def compiled_method(locals_keys)
|
239
|
-
|
240
|
-
compile_template_method(locals_keys)
|
219
|
+
LOCK.synchronize do
|
220
|
+
@compiled_method[locals_keys] ||= compile_template_method(locals_keys)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def local_extraction(local_keys)
|
225
|
+
local_keys.map do |k|
|
226
|
+
if k.to_s =~ /\A[a-z_][a-zA-Z_0-9]*\z/
|
227
|
+
"#{k} = locals[#{k.inspect}]"
|
228
|
+
else
|
229
|
+
raise "invalid locals key: #{k.inspect} (keys must be variable names)"
|
230
|
+
end
|
231
|
+
end.join("\n")
|
241
232
|
end
|
242
233
|
|
243
|
-
|
244
|
-
|
245
|
-
|
234
|
+
def compile_template_method(local_keys)
|
235
|
+
source, offset = precompiled(local_keys)
|
236
|
+
local_code = local_extraction(local_keys)
|
237
|
+
|
246
238
|
method_name = "__tilt_#{Thread.current.object_id.abs}"
|
247
239
|
method_source = ""
|
248
240
|
|
@@ -257,11 +249,12 @@ module Tilt
|
|
257
249
|
class << self
|
258
250
|
this, locals = Thread.current[:tilt_vars]
|
259
251
|
this.instance_eval do
|
252
|
+
#{local_code}
|
260
253
|
RUBY
|
261
254
|
offset += method_source.count("\n")
|
262
255
|
method_source << source
|
263
256
|
method_source << "\nend;end;end;end"
|
264
|
-
Object.class_eval
|
257
|
+
Object.class_eval(method_source, eval_file, line - offset)
|
265
258
|
unbind_compiled_method(method_name)
|
266
259
|
end
|
267
260
|
|
@@ -276,7 +269,7 @@ module Tilt
|
|
276
269
|
end
|
277
270
|
|
278
271
|
def extract_magic_comment(script)
|
279
|
-
binary
|
272
|
+
binary(script) do
|
280
273
|
script[/\A[ \t]*\#.*coding\s*[=:]\s*([[:alnum:]\-_]+).*$/n, 1]
|
281
274
|
end
|
282
275
|
end
|