ezml 0.1.1
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/.DS_Store +0 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +149 -0
- data/LICENSE.txt +21 -0
- data/README.md +140 -0
- data/Rakefile +6 -0
- data/bin/ezml +9 -0
- data/examples/helloworld.ezml +44 -0
- data/examples/helloworld.html +61 -0
- data/examples/template.ezml +69 -0
- data/examples/template.html +102 -0
- data/ezml.gemspec +40 -0
- data/lib/ezml.rb +8 -0
- data/lib/ezml/attribute_builder.rb +141 -0
- data/lib/ezml/attribute_compiler.rb +172 -0
- data/lib/ezml/attribute_parser.rb +133 -0
- data/lib/ezml/buffer.rb +166 -0
- data/lib/ezml/compiler.rb +322 -0
- data/lib/ezml/engine.rb +107 -0
- data/lib/ezml/error.rb +59 -0
- data/lib/ezml/escapable.rb +46 -0
- data/lib/ezml/exec.rb +348 -0
- data/lib/ezml/filters.rb +249 -0
- data/lib/ezml/generator.rb +38 -0
- data/lib/ezml/helpers.rb +299 -0
- data/lib/ezml/options.rb +142 -0
- data/lib/ezml/parser.rb +826 -0
- data/lib/ezml/template_engine.rb +106 -0
- data/lib/ezml/temple_line_counter.rb +26 -0
- data/lib/ezml/util.rb +156 -0
- data/lib/ezml/version.rb +3 -0
- metadata +199 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module EZML
|
2
|
+
|
3
|
+
class Escapable < Temple::Filter
|
4
|
+
def initialize(*)
|
5
|
+
super
|
6
|
+
@escape_code = "::EZML::Helpers.html_escape((%s))"
|
7
|
+
@escaper = eval("proc {|v| #{@escape_code % 'v'} }")
|
8
|
+
@once_escape_code = "::EZML::Helpers.escape_once((%s))"
|
9
|
+
@once_escaper = eval("proc {|v| #{@once_escape_code % 'v'} }")
|
10
|
+
@escape = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_escape(flag, exp)
|
14
|
+
old = @escape
|
15
|
+
@escape = flag
|
16
|
+
compile(exp)
|
17
|
+
ensure
|
18
|
+
@escape = old
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_static(value)
|
22
|
+
[:static,
|
23
|
+
if @escape == :once
|
24
|
+
@once_escaper[value]
|
25
|
+
elsif @escape
|
26
|
+
@escaper[value]
|
27
|
+
else
|
28
|
+
value
|
29
|
+
end
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_dynamic(value)
|
34
|
+
[:dynamic,
|
35
|
+
if @escape == :once
|
36
|
+
@once_escape_code % value
|
37
|
+
elsif @escape
|
38
|
+
@escape_code % value
|
39
|
+
else
|
40
|
+
"(#{value}).to_s"
|
41
|
+
end
|
42
|
+
]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/lib/ezml/exec.rb
ADDED
@@ -0,0 +1,348 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'optparse'
|
3
|
+
require 'rbconfig'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
module EZML
|
7
|
+
# This module handles the various EZML executables (`ezml` and `ezml-convert`).
|
8
|
+
module Exec
|
9
|
+
# An abstract class that encapsulates the executable code for all three executables.
|
10
|
+
class Generic
|
11
|
+
# @param args [Array<String>] The command-line arguments
|
12
|
+
def initialize(args)
|
13
|
+
@args = args
|
14
|
+
@options = {:for_engine => {}}
|
15
|
+
end
|
16
|
+
|
17
|
+
# Parses the command-line arguments and runs the executable.
|
18
|
+
# Calls `Kernel#exit` at the end, so it never returns.
|
19
|
+
#
|
20
|
+
# @see #parse
|
21
|
+
def parse!
|
22
|
+
begin
|
23
|
+
parse
|
24
|
+
rescue Exception => e
|
25
|
+
raise e if @options[:trace] || e.is_a?(SystemExit)
|
26
|
+
|
27
|
+
$stderr.print "#{e.class}: " unless e.class == RuntimeError
|
28
|
+
$stderr.puts "#{e.message}"
|
29
|
+
$stderr.puts " Use --trace for backtrace."
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
exit 0
|
33
|
+
end
|
34
|
+
|
35
|
+
# Parses the command-line arguments and runs the executable.
|
36
|
+
# This does not handle exceptions or exit the program.
|
37
|
+
#
|
38
|
+
# @see #parse!
|
39
|
+
def parse
|
40
|
+
@opts = OptionParser.new(&method(:set_opts))
|
41
|
+
@opts.parse!(@args)
|
42
|
+
|
43
|
+
process_result
|
44
|
+
|
45
|
+
@options
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [String] A description of the executable
|
49
|
+
def to_s
|
50
|
+
@opts.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
# Finds the line of the source template
|
56
|
+
# on which an exception was raised.
|
57
|
+
#
|
58
|
+
# @param exception [Exception] The exception
|
59
|
+
# @return [String] The line number
|
60
|
+
def get_line(exception)
|
61
|
+
# SyntaxErrors have weird line reporting
|
62
|
+
# when there's trailing whitespace,
|
63
|
+
# which there is for EZML documents.
|
64
|
+
return (exception.message.scan(/:(\d+)/).first || ["??"]).first if exception.is_a?(::SyntaxError)
|
65
|
+
(exception.backtrace[0].scan(/:(\d+)/).first || ["??"]).first
|
66
|
+
end
|
67
|
+
|
68
|
+
# Tells optparse how to parse the arguments
|
69
|
+
# available for all executables.
|
70
|
+
#
|
71
|
+
# This is meant to be overridden by subclasses
|
72
|
+
# so they can add their own options.
|
73
|
+
#
|
74
|
+
# @param opts [OptionParser]
|
75
|
+
def set_opts(opts)
|
76
|
+
opts.on('-s', '--stdin', :NONE, 'Read input from standard input instead of an input file') do
|
77
|
+
@options[:input] = $stdin
|
78
|
+
end
|
79
|
+
|
80
|
+
opts.on('--trace', :NONE, 'Show a full traceback on error') do
|
81
|
+
@options[:trace] = true
|
82
|
+
end
|
83
|
+
|
84
|
+
opts.on('--unix-newlines', 'Use Unix-style newlines in written files.') do
|
85
|
+
# Note that this is the preferred way to check for Windows, since
|
86
|
+
# JRuby and Rubinius also run there.
|
87
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin|windows|mingw/i
|
88
|
+
@options[:unix_newlines] = true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
opts.on_tail("-?", "-h", "--help", "Show this message") do
|
93
|
+
puts opts
|
94
|
+
exit
|
95
|
+
end
|
96
|
+
|
97
|
+
opts.on_tail("-v", "--version", "Print version") do
|
98
|
+
puts("EZML #{::EZML::VERSION}")
|
99
|
+
exit
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Processes the options set by the command-line arguments.
|
104
|
+
# In particular, sets `@options[:input]` and `@options[:output]`
|
105
|
+
# to appropriate IO streams.
|
106
|
+
#
|
107
|
+
# This is meant to be overridden by subclasses
|
108
|
+
# so they can run their respective programs.
|
109
|
+
def process_result
|
110
|
+
input, output = @options[:input], @options[:output]
|
111
|
+
args = @args.dup
|
112
|
+
input ||=
|
113
|
+
begin
|
114
|
+
filename = args.shift
|
115
|
+
@options[:filename] = filename
|
116
|
+
open_file(filename) || $stdin
|
117
|
+
end
|
118
|
+
output ||= open_file(args.shift, 'w') || $stdout
|
119
|
+
|
120
|
+
@options[:input], @options[:output] = input, output
|
121
|
+
end
|
122
|
+
|
123
|
+
COLORS = { :red => 31, :green => 32, :yellow => 33 }
|
124
|
+
|
125
|
+
# Prints a status message about performing the given action,
|
126
|
+
# colored using the given color (via terminal escapes) if possible.
|
127
|
+
#
|
128
|
+
# @param name [#to_s] A short name for the action being performed.
|
129
|
+
# Shouldn't be longer than 11 characters.
|
130
|
+
# @param color [Symbol] The name of the color to use for this action.
|
131
|
+
# Can be `:red`, `:green`, or `:yellow`.
|
132
|
+
def puts_action(name, color, arg)
|
133
|
+
return if @options[:for_engine][:quiet]
|
134
|
+
printf color(color, "%11s %s\n"), name, arg
|
135
|
+
end
|
136
|
+
|
137
|
+
# Same as `Kernel.puts`, but doesn't print anything if the `--quiet` option is set.
|
138
|
+
#
|
139
|
+
# @param args [Array] Passed on to `Kernel.puts`
|
140
|
+
def puts(*args)
|
141
|
+
return if @options[:for_engine][:quiet]
|
142
|
+
Kernel.puts(*args)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Wraps the given string in terminal escapes
|
146
|
+
# causing it to have the given color.
|
147
|
+
# If terminal esapes aren't supported on this platform,
|
148
|
+
# just returns the string instead.
|
149
|
+
#
|
150
|
+
# @param color [Symbol] The name of the color to use.
|
151
|
+
# Can be `:red`, `:green`, or `:yellow`.
|
152
|
+
# @param str [String] The string to wrap in the given color.
|
153
|
+
# @return [String] The wrapped string.
|
154
|
+
def color(color, str)
|
155
|
+
raise "[BUG] Unrecognized color #{color}" unless COLORS[color]
|
156
|
+
|
157
|
+
# Almost any real Unix terminal will support color,
|
158
|
+
# so we just filter for Windows terms (which don't set TERM)
|
159
|
+
# and not-real terminals, which aren't ttys.
|
160
|
+
return str if ENV["TERM"].nil? || ENV["TERM"].empty? || !STDOUT.tty?
|
161
|
+
return "\e[#{COLORS[color]}m#{str}\e[0m"
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def open_file(filename, flag = 'r')
|
167
|
+
return if filename.nil?
|
168
|
+
flag = 'wb' if @options[:unix_newlines] && flag == 'w'
|
169
|
+
File.open(filename, flag)
|
170
|
+
end
|
171
|
+
|
172
|
+
def handle_load_error(err)
|
173
|
+
dep = err.message[/^no such file to load -- (.*)/, 1]
|
174
|
+
raise err if @options[:trace] || dep.nil? || dep.empty?
|
175
|
+
$stderr.puts <<MESSAGE
|
176
|
+
Required dependency #{dep} not found!
|
177
|
+
Run "gem install #{dep}" to get it.
|
178
|
+
Use --trace for backtrace.
|
179
|
+
MESSAGE
|
180
|
+
exit 1
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# The `ezml` executable.
|
185
|
+
class EZML < Generic
|
186
|
+
# @param args [Array<String>] The command-line arguments
|
187
|
+
def initialize(args)
|
188
|
+
super
|
189
|
+
@options[:for_engine] = {}
|
190
|
+
@options[:requires] = []
|
191
|
+
@options[:load_paths] = []
|
192
|
+
end
|
193
|
+
|
194
|
+
# Tells optparse how to parse the arguments.
|
195
|
+
#
|
196
|
+
# @param opts [OptionParser]
|
197
|
+
def set_opts(opts)
|
198
|
+
super
|
199
|
+
|
200
|
+
opts.banner = <<END
|
201
|
+
Usage: ezml [options] [INPUT] [OUTPUT]
|
202
|
+
|
203
|
+
Description:
|
204
|
+
Converts EZML files to HTML.
|
205
|
+
|
206
|
+
Options:
|
207
|
+
END
|
208
|
+
|
209
|
+
opts.on('-c', '--check', "Just check syntax, don't evaluate.") do
|
210
|
+
require 'stringio'
|
211
|
+
@options[:check_syntax] = true
|
212
|
+
@options[:output] = StringIO.new
|
213
|
+
end
|
214
|
+
|
215
|
+
opts.on('-f', '--format NAME',
|
216
|
+
'Output format. Can be html5 (default), xhtml, or html4.') do |name|
|
217
|
+
@options[:for_engine][:format] = name.to_sym
|
218
|
+
end
|
219
|
+
|
220
|
+
opts.on('-e', '--escape-html',
|
221
|
+
'Escape HTML characters (like ampersands and angle brackets) by default.') do
|
222
|
+
@options[:for_engine][:escape_html] = true
|
223
|
+
end
|
224
|
+
|
225
|
+
opts.on('--no-escape-attrs',
|
226
|
+
"Don't escape HTML characters (like ampersands and angle brackets) in attributes.") do
|
227
|
+
@options[:for_engine][:escape_attrs] = false
|
228
|
+
end
|
229
|
+
|
230
|
+
opts.on('-q', '--double-quote-attributes',
|
231
|
+
'Set attribute wrapper to double-quotes (default is single).') do
|
232
|
+
@options[:for_engine][:attr_wrapper] = '"'
|
233
|
+
end
|
234
|
+
|
235
|
+
opts.on('--remove-whitespace',
|
236
|
+
'Remove whitespace surrounding and within tags') do
|
237
|
+
@options[:for_engine][:remove_whitespace] = true
|
238
|
+
end
|
239
|
+
|
240
|
+
opts.on('--cdata',
|
241
|
+
'Always add CDATA sections to javascript and css blocks.') do
|
242
|
+
@options[:for_engine][:cdata] = true
|
243
|
+
end
|
244
|
+
|
245
|
+
opts.on('--autoclose LIST',
|
246
|
+
'Comma separated list of elements to be automatically self-closed.') do |list|
|
247
|
+
@options[:for_engine][:autoclose] = list.split(',')
|
248
|
+
end
|
249
|
+
|
250
|
+
opts.on('--suppress-eval',
|
251
|
+
'Don\'t evaluate Ruby scripts.') do
|
252
|
+
@options[:for_engine][:suppress_eval] = true
|
253
|
+
end
|
254
|
+
|
255
|
+
opts.on('-r', '--require FILE', "Same as 'ruby -r'.") do |file|
|
256
|
+
@options[:requires] << file
|
257
|
+
end
|
258
|
+
|
259
|
+
opts.on('-I', '--load-path PATH', "Same as 'ruby -I'.") do |path|
|
260
|
+
@options[:load_paths] << path
|
261
|
+
end
|
262
|
+
|
263
|
+
opts.on('-E ex[:in]', 'Specify the default external and internal character encodings.') do |encoding|
|
264
|
+
external, internal = encoding.split(':')
|
265
|
+
Encoding.default_external = external if external && !external.empty?
|
266
|
+
Encoding.default_internal = internal if internal && !internal.empty?
|
267
|
+
end
|
268
|
+
|
269
|
+
opts.on('-d', '--debug', "Print out the precompiled Ruby source, and show syntax errors in the Ruby code.") do
|
270
|
+
@options[:debug] = true
|
271
|
+
end
|
272
|
+
|
273
|
+
opts.on('-p', '--parse', "Print out EZML parse tree.") do
|
274
|
+
@options[:parse] = true
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
# Processes the options set by the command-line arguments,
|
280
|
+
# and runs the EZML compiler appropriately.
|
281
|
+
def process_result
|
282
|
+
super
|
283
|
+
@options[:for_engine][:filename] = @options[:filename]
|
284
|
+
input = @options[:input]
|
285
|
+
output = @options[:output]
|
286
|
+
|
287
|
+
template = input.read()
|
288
|
+
input.close() if input.is_a? File
|
289
|
+
|
290
|
+
@options[:load_paths].each {|p| $LOAD_PATH << p}
|
291
|
+
@options[:requires].each {|f| require f}
|
292
|
+
|
293
|
+
begin
|
294
|
+
|
295
|
+
if @options[:parse]
|
296
|
+
parser = ::EZML::Parser.new(::EZML::Options.new(@options))
|
297
|
+
pp parser.call(template)
|
298
|
+
return
|
299
|
+
end
|
300
|
+
|
301
|
+
engine = ::EZML::Engine.new(template, @options[:for_engine])
|
302
|
+
|
303
|
+
if @options[:check_syntax]
|
304
|
+
error = validate_ruby(engine.precompiled)
|
305
|
+
if error
|
306
|
+
puts error.message.split("\n").first
|
307
|
+
exit 1
|
308
|
+
end
|
309
|
+
puts "Syntax OK"
|
310
|
+
return
|
311
|
+
end
|
312
|
+
|
313
|
+
if @options[:debug]
|
314
|
+
puts engine.precompiled
|
315
|
+
error = validate_ruby(engine.precompiled)
|
316
|
+
if error
|
317
|
+
puts '=' * 100
|
318
|
+
puts error.message.split("\n")[0]
|
319
|
+
exit 1
|
320
|
+
end
|
321
|
+
return
|
322
|
+
end
|
323
|
+
|
324
|
+
result = engine.to_html
|
325
|
+
rescue Exception => e
|
326
|
+
raise e if @options[:trace]
|
327
|
+
|
328
|
+
case e
|
329
|
+
when ::EZML::SyntaxError; raise "Syntax error on line #{get_line e}: #{e.message}"
|
330
|
+
when ::EZML::Error; raise "EZML error on line #{get_line e}: #{e.message}"
|
331
|
+
else raise "Exception on line #{get_line e}: #{e.message}"
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
output.write(result)
|
336
|
+
output.close() if output.is_a? File
|
337
|
+
end
|
338
|
+
|
339
|
+
def validate_ruby(code)
|
340
|
+
begin
|
341
|
+
eval("BEGIN {return nil}; #{code}", binding, @options[:filename] || "")
|
342
|
+
rescue ::SyntaxError # Not to be confused with EZML::SyntaxError
|
343
|
+
$!
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
data/lib/ezml/filters.rb
ADDED
@@ -0,0 +1,249 @@
|
|
1
|
+
require "tilt"
|
2
|
+
|
3
|
+
module EZML
|
4
|
+
module Filters
|
5
|
+
|
6
|
+
extend self
|
7
|
+
|
8
|
+
attr_reader :defined
|
9
|
+
@defined = {}
|
10
|
+
|
11
|
+
def register_tilt_filter(name, options = {})
|
12
|
+
if constants.map(&:to_s).include?(name.to_s)
|
13
|
+
raise "#{name} filter already defined"
|
14
|
+
end
|
15
|
+
|
16
|
+
filter = const_set(name, Module.new)
|
17
|
+
filter.extend const_get(options[:extend] || "Plain")
|
18
|
+
filter.extend TiltFilter
|
19
|
+
filter.extend PrecompiledTiltFilter if options.has_key? :precompiled
|
20
|
+
|
21
|
+
if options.has_key? :template_class
|
22
|
+
filter.template_class = options[:template_class]
|
23
|
+
else
|
24
|
+
filter.tilt_extension = options.fetch(:extension) { name.downcase }
|
25
|
+
end
|
26
|
+
|
27
|
+
# All ":coffeescript" as alias for ":coffee", etc.
|
28
|
+
if options.has_key?(:alias)
|
29
|
+
[options[:alias]].flatten.each {|x| Filters.defined[x.to_s] = filter}
|
30
|
+
end
|
31
|
+
filter
|
32
|
+
end
|
33
|
+
|
34
|
+
def remove_filter(name)
|
35
|
+
defined.delete name.to_s.downcase
|
36
|
+
if constants.map(&:to_s).include?(name.to_s)
|
37
|
+
remove_const name.to_sym
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Base
|
42
|
+
|
43
|
+
def self.included(base)
|
44
|
+
Filters.defined[base.name.split("::").last.downcase] = base
|
45
|
+
base.extend(base)
|
46
|
+
end
|
47
|
+
|
48
|
+
def render(text)
|
49
|
+
raise Error.new("#{self.inspect}#render not defined!")
|
50
|
+
end
|
51
|
+
|
52
|
+
def render_with_options(text, options)
|
53
|
+
render(text)
|
54
|
+
end
|
55
|
+
|
56
|
+
def internal_compile(*args)
|
57
|
+
compile(*args)
|
58
|
+
end
|
59
|
+
|
60
|
+
def compile(compiler, text)
|
61
|
+
filter = self
|
62
|
+
compiler.instance_eval do
|
63
|
+
if contains_interpolation?(text)
|
64
|
+
return if options[:suppress_eval]
|
65
|
+
|
66
|
+
text = unescape_interpolation(text, options[:escape_html]).gsub(/(\\+)n/) do |s|
|
67
|
+
escapes = $1.size
|
68
|
+
next s if escapes % 2 == 0
|
69
|
+
"#{'\\' * (escapes - 1)}\n"
|
70
|
+
end
|
71
|
+
text = %[\n#{text.sub(/\n"\Z/, "\\n\"")}]
|
72
|
+
push_script <<RUBY.rstrip, :escape_html => false
|
73
|
+
find_and_preserve(#{filter.inspect}.render_with_options(#{text}, _ezmlout.options))
|
74
|
+
RUBY
|
75
|
+
return
|
76
|
+
end
|
77
|
+
|
78
|
+
rendered = EZML::Helpers::find_and_preserve(filter.render_with_options(text.to_s, compiler.options), compiler.options[:preserve])
|
79
|
+
push_text("#{rendered.rstrip}\n")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
module Plain
|
85
|
+
include Base
|
86
|
+
|
87
|
+
def render(text); text; end
|
88
|
+
end
|
89
|
+
|
90
|
+
module Javascript
|
91
|
+
include Base
|
92
|
+
|
93
|
+
# @see Base#render_with_options
|
94
|
+
def render_with_options(text, options)
|
95
|
+
indent = options[:cdata] ? ' ' : ' ' # 4 or 2 spaces
|
96
|
+
if options[:format] == :html5
|
97
|
+
type = ''
|
98
|
+
else
|
99
|
+
type = " type=#{options[:attr_wrapper]}text/javascript#{options[:attr_wrapper]}"
|
100
|
+
end
|
101
|
+
|
102
|
+
text = text.rstrip
|
103
|
+
text.gsub!("\n", "\n#{indent}")
|
104
|
+
|
105
|
+
%!<script#{type}>\n#{" //<![CDATA[\n" if options[:cdata]}#{indent}#{text}\n#{" //]]>\n" if options[:cdata]}</script>!
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
module Css
|
110
|
+
include Base
|
111
|
+
|
112
|
+
# @see Base#render_with_options
|
113
|
+
def render_with_options(text, options)
|
114
|
+
indent = options[:cdata] ? ' ' : ' ' # 4 or 2 spaces
|
115
|
+
if options[:format] == :html5
|
116
|
+
type = ''
|
117
|
+
else
|
118
|
+
type = " type=#{options[:attr_wrapper]}text/css#{options[:attr_wrapper]}"
|
119
|
+
end
|
120
|
+
|
121
|
+
text = text.rstrip
|
122
|
+
text.gsub!("\n", "\n#{indent}")
|
123
|
+
|
124
|
+
%(<style#{type}>\n#{" /*<![CDATA[*/\n" if options[:cdata]}#{indent}#{text}\n#{" /*]]>*/\n" if options[:cdata]}</style>)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
module Cdata
|
129
|
+
include Base
|
130
|
+
|
131
|
+
# @see Base#render
|
132
|
+
def render(text)
|
133
|
+
"<![CDATA[#{"\n#{text.rstrip}".gsub("\n", "\n ")}\n]]>"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
module Escaped
|
138
|
+
include Base
|
139
|
+
|
140
|
+
# @see Base#render
|
141
|
+
def render(text)
|
142
|
+
EZML::Helpers.html_escape text
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
module Ruby
|
147
|
+
include Base
|
148
|
+
require 'stringio'
|
149
|
+
|
150
|
+
# @see Base#compile
|
151
|
+
def compile(compiler, text)
|
152
|
+
return if compiler.options[:suppress_eval]
|
153
|
+
compiler.instance_eval do
|
154
|
+
push_silent "#{<<-FIRST.tr("\n", ';')}#{text}#{<<-LAST.tr("\n", ';')}"
|
155
|
+
begin
|
156
|
+
ezml_io = StringIO.new(_ezmlout.buffer, 'a')
|
157
|
+
FIRST
|
158
|
+
ensure
|
159
|
+
ezml_io.close
|
160
|
+
ezml_io = nil
|
161
|
+
end
|
162
|
+
LAST
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
module Preserve
|
168
|
+
include Base
|
169
|
+
|
170
|
+
# @see Base#render
|
171
|
+
def render(text)
|
172
|
+
EZML::Helpers.preserve text
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
module TiltFilter
|
177
|
+
extend self
|
178
|
+
attr_accessor :tilt_extension, :options
|
179
|
+
attr_writer :template_class
|
180
|
+
|
181
|
+
def template_class
|
182
|
+
(@template_class if defined? @template_class) or begin
|
183
|
+
@template_class = Tilt["t.#{tilt_extension}"] or
|
184
|
+
raise Error.new(Error.message(:cant_run_filter, tilt_extension))
|
185
|
+
rescue LoadError => e
|
186
|
+
dep = e.message.split('--').last.strip
|
187
|
+
raise Error.new(Error.message(:gem_install_filter_deps, tilt_extension, dep))
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.extended(base)
|
192
|
+
base.options = {}
|
193
|
+
base.instance_eval %Q{
|
194
|
+
include Base
|
195
|
+
|
196
|
+
def render_with_options(text, compiler_options)
|
197
|
+
text = template_class.new(nil, 1, options) {text}.render
|
198
|
+
super(text, compiler_options)
|
199
|
+
end
|
200
|
+
}
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
module PrecompiledTiltFilter
|
205
|
+
def precompiled(text)
|
206
|
+
template_class.new(nil, 1, options) { text }.send(:precompiled, {}).first
|
207
|
+
end
|
208
|
+
|
209
|
+
def compile(compiler, text)
|
210
|
+
return if compiler.options[:suppress_eval]
|
211
|
+
compiler.send(:push_script, precompiled(text))
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# @!parse module Sass; end
|
216
|
+
register_tilt_filter "Sass", :extend => "Css"
|
217
|
+
|
218
|
+
# @!parse module Scss; end
|
219
|
+
register_tilt_filter "Scss", :extend => "Css"
|
220
|
+
|
221
|
+
# @!parse module Less; end
|
222
|
+
register_tilt_filter "Less", :extend => "Css"
|
223
|
+
|
224
|
+
# @!parse module Markdown; end
|
225
|
+
register_tilt_filter "Markdown"
|
226
|
+
|
227
|
+
# @!parse module Erb; end
|
228
|
+
register_tilt_filter "Erb", :precompiled => true
|
229
|
+
|
230
|
+
# @!parse module Coffee; end
|
231
|
+
register_tilt_filter "Coffee", :alias => "coffeescript", :extend => "Javascript"
|
232
|
+
|
233
|
+
module Erb
|
234
|
+
class << self
|
235
|
+
def precompiled(text)
|
236
|
+
#workaround for https://github.com/rtomayko/tilt/pull/183
|
237
|
+
require 'erubis' if (defined?(::Erubis) && !defined?(::Erubis::Eruby))
|
238
|
+
super.sub(/^#coding:.*?\n/, '')
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
begin
|
246
|
+
#{}require_relative "filters/maruku"
|
247
|
+
#{}require_relative "filters/textile"
|
248
|
+
rescue LoadError
|
249
|
+
end
|