forked from rtomayko/tilt
/
tilt.rb
204 lines (163 loc) · 5.43 KB
/
tilt.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
module Tilt
VERSION = '1.3.6'
@preferred_mappings = Hash.new
@template_mappings = Hash.new { |h, k| h[k] = [] }
# Hash of template path pattern => template implementation class mappings.
def self.mappings
@template_mappings
end
def self.normalize(ext)
ext.to_s.downcase.sub(/^\./, '')
end
# Register a template implementation by file extension.
def self.register(template_class, *extensions)
if template_class.respond_to?(:to_str)
# Support register(ext, template_class) too
extensions, template_class = [template_class], extensions[0]
end
extensions.each do |ext|
ext = normalize(ext)
mappings[ext].unshift(template_class).uniq!
end
end
# Makes a template class preferred for the given file extensions. If you
# don't provide any extensions, it will be preferred for all its already
# registered extensions:
#
# # Prefer RDiscount for its registered file extensions:
# Tilt.prefer(Tilt::RDiscountTemplate)
#
# # Prefer RDiscount only for the .md extensions:
# Tilt.prefer(Tilt::RDiscountTemplate, '.md')
def self.prefer(template_class, *extensions)
if extensions.empty?
mappings.each do |ext, klasses|
@preferred_mappings[ext] = template_class if klasses.include? template_class
end
else
extensions.each do |ext|
ext = normalize(ext)
register(template_class, ext)
@preferred_mappings[ext] = template_class
end
end
end
# Returns true when a template exists on an exact match of the provided file extension
def self.registered?(ext)
mappings.key?(ext.downcase) && !mappings[ext.downcase].empty?
end
# Create a new template for the given file using the file's extension
# to determine the the template mapping.
def self.new(file, line=nil, options={}, &block)
if template_class = self[file]
template_class.new(file, line, options, &block)
else
fail "No template engine registered for #{File.basename(file)}"
end
end
# Lookup a template class for the given filename or file
# extension. Return nil when no implementation is found.
def self.[](file)
pattern = file.to_s.downcase
until pattern.empty? || registered?(pattern)
pattern = File.basename(pattern)
pattern.sub!(/^[^.]*\.?/, '')
end
# Try to find a preferred engine.
preferred_klass = @preferred_mappings[pattern]
return preferred_klass if preferred_klass
# Fall back to the general list of mappings.
klasses = @template_mappings[pattern]
# Try to find an engine which is already loaded.
template = klasses.detect do |klass|
if klass.respond_to?(:engine_initialized?)
klass.engine_initialized?
end
end
return template if template
# Try each of the classes until one succeeds. If all of them fails,
# we'll raise the error of the first class.
first_failure = nil
klasses.each do |klass|
begin
klass.new { '' }
rescue Exception => ex
first_failure ||= ex
next
else
return klass
end
end
raise first_failure if first_failure
end
# Deprecated module.
module CompileSite
end
# Extremely simple template cache implementation. Calling applications
# create a Tilt::Cache instance and use #fetch with any set of hashable
# arguments (such as those to Tilt.new):
# cache = Tilt::Cache.new
# cache.fetch(path, line, options) { Tilt.new(path, line, options) }
#
# Subsequent invocations return the already loaded template object.
class Cache
def initialize
@cache = {}
end
def fetch(*key)
@cache[key] ||= yield
end
def clear
@cache = {}
end
end
# Template Implementations ================================================
require 'tilt/string'
register StringTemplate, 'str'
require 'tilt/erb'
register ERBTemplate, 'erb', 'rhtml'
register ErubisTemplate, 'erb', 'rhtml', 'erubis'
require 'tilt/etanni'
register EtanniTemplate, 'etn', 'etanni'
require 'tilt/haml'
register HamlTemplate, 'haml'
require 'tilt/css'
register SassTemplate, 'sass'
register ScssTemplate, 'scss'
register LessTemplate, 'less'
require 'tilt/csv'
register CSVTemplate, 'rcsv'
require 'tilt/coffee'
register CoffeeScriptTemplate, 'coffee'
require 'tilt/nokogiri'
register NokogiriTemplate, 'nokogiri'
require 'tilt/builder'
register BuilderTemplate, 'builder'
require 'tilt/markaby'
register MarkabyTemplate, 'mab'
require 'tilt/liquid'
register LiquidTemplate, 'liquid'
require 'tilt/radius'
register RadiusTemplate, 'radius'
require 'tilt/markdown'
register MarukuTemplate, 'markdown', 'mkd', 'md'
register KramdownTemplate, 'markdown', 'mkd', 'md'
register BlueClothTemplate, 'markdown', 'mkd', 'md'
register RDiscountTemplate, 'markdown', 'mkd', 'md'
register RedcarpetTemplate::Redcarpet1, 'markdown', 'mkd', 'md'
register RedcarpetTemplate::Redcarpet2, 'markdown', 'mkd', 'md'
register RedcarpetTemplate, 'markdown', 'mkd', 'md'
require 'tilt/textile'
register RedClothTemplate, 'textile'
require 'tilt/rdoc'
register RDocTemplate, 'rdoc'
require 'tilt/wiki'
register CreoleTemplate, 'wiki', 'creole'
register WikiClothTemplate, 'wiki', 'mediawiki', 'mw'
require 'tilt/yajl'
register YajlTemplate, 'yajl'
require 'tilt/asciidoc'
register AsciidoctorTemplate, 'ad', 'adoc', 'asciidoc'
require 'tilt/plain'
register PlainTemplate, 'html'
end