haml 5.0.3 → 5.2.0
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 +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +50 -25
- data/.yardopts +1 -2
- data/CHANGELOG.md +44 -1
- data/Gemfile +2 -5
- data/MIT-LICENSE +2 -2
- data/README.md +4 -5
- data/REFERENCE.md +27 -4
- data/Rakefile +2 -13
- data/benchmark.rb +13 -9
- data/haml.gemspec +10 -3
- data/lib/haml.rb +1 -0
- data/lib/haml/attribute_builder.rb +4 -3
- data/lib/haml/attribute_compiler.rb +43 -31
- data/lib/haml/attribute_parser.rb +6 -4
- data/lib/haml/buffer.rb +4 -1
- data/lib/haml/compiler.rb +23 -24
- data/lib/haml/engine.rb +12 -3
- data/lib/haml/error.rb +25 -24
- data/lib/haml/escapable.rb +39 -11
- data/lib/haml/exec.rb +5 -6
- data/lib/haml/filters.rb +12 -11
- data/lib/haml/generator.rb +2 -1
- data/lib/haml/helpers.rb +15 -13
- data/lib/haml/helpers/action_view_extensions.rb +1 -0
- data/lib/haml/helpers/action_view_mods.rb +4 -1
- data/lib/haml/helpers/action_view_xss_mods.rb +1 -0
- data/lib/haml/helpers/safe_erubi_template.rb +1 -0
- data/lib/haml/helpers/safe_erubis_template.rb +1 -0
- data/lib/haml/helpers/xss_mods.rb +7 -3
- data/lib/haml/options.rb +36 -36
- data/lib/haml/parser.rb +21 -19
- data/lib/haml/plugin.rb +7 -4
- data/lib/haml/railtie.rb +4 -4
- data/lib/haml/sass_rails_filter.rb +1 -0
- data/lib/haml/template.rb +1 -0
- data/lib/haml/template/options.rb +1 -0
- data/lib/haml/temple_engine.rb +11 -9
- data/lib/haml/temple_line_counter.rb +1 -0
- data/lib/haml/util.rb +5 -5
- data/lib/haml/version.rb +2 -1
- metadata +28 -10
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'haml/attribute_parser'
|
3
4
|
|
4
5
|
module Haml
|
@@ -6,27 +7,7 @@ module Haml
|
|
6
7
|
# @param type [Symbol] :static or :dynamic
|
7
8
|
# @param key [String]
|
8
9
|
# @param value [String] Actual string value for :static type, value's Ruby literal for :dynamic type.
|
9
|
-
|
10
|
-
# @return [String] A Ruby literal of value.
|
11
|
-
def to_literal
|
12
|
-
case type
|
13
|
-
when :static
|
14
|
-
Haml::Util.inspect_obj(value)
|
15
|
-
when :dynamic
|
16
|
-
value
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Returns a script to render attributes on runtime.
|
22
|
-
#
|
23
|
-
# @param attributes [Hash]
|
24
|
-
# @param object_ref [String,:nil]
|
25
|
-
# @param dynamic_attributes [DynamicAttributes]
|
26
|
-
# @return [String] Attributes rendering code
|
27
|
-
def self.runtime_build(attributes, object_ref, dynamic_attributes)
|
28
|
-
"_hamlout.attributes(#{Haml::Util.inspect_obj(attributes)}, #{object_ref},#{dynamic_attributes.to_literal})"
|
29
|
-
end
|
10
|
+
AttributeValue = Struct.new(:type, :key, :value)
|
30
11
|
|
31
12
|
# @param options [Haml::Options]
|
32
13
|
def initialize(options)
|
@@ -40,16 +21,16 @@ module Haml
|
|
40
21
|
#
|
41
22
|
# @param attributes [Hash]
|
42
23
|
# @param object_ref [String,:nil]
|
43
|
-
# @param dynamic_attributes [DynamicAttributes]
|
24
|
+
# @param dynamic_attributes [Haml::Parser::DynamicAttributes]
|
44
25
|
# @return [Array] Temple expression
|
45
26
|
def compile(attributes, object_ref, dynamic_attributes)
|
46
27
|
if object_ref != :nil || !AttributeParser.available?
|
47
|
-
return [:dynamic,
|
28
|
+
return [:dynamic, compile_runtime_build(attributes, object_ref, dynamic_attributes)]
|
48
29
|
end
|
49
30
|
|
50
31
|
parsed_hashes = [dynamic_attributes.new, dynamic_attributes.old].compact.map do |attribute_hash|
|
51
32
|
unless (hash = AttributeParser.parse(attribute_hash))
|
52
|
-
return [:dynamic,
|
33
|
+
return [:dynamic, compile_runtime_build(attributes, object_ref, dynamic_attributes)]
|
53
34
|
end
|
54
35
|
hash
|
55
36
|
end
|
@@ -63,6 +44,16 @@ module Haml
|
|
63
44
|
|
64
45
|
private
|
65
46
|
|
47
|
+
# Returns a script to render attributes on runtime.
|
48
|
+
#
|
49
|
+
# @param attributes [Hash]
|
50
|
+
# @param object_ref [String,:nil]
|
51
|
+
# @param dynamic_attributes [Haml::Parser::DynamicAttributes]
|
52
|
+
# @return [String] Attributes rendering code
|
53
|
+
def compile_runtime_build(attributes, object_ref, dynamic_attributes)
|
54
|
+
"_hamlout.attributes(#{to_literal(attributes)}, #{object_ref}, #{dynamic_attributes.to_literal})"
|
55
|
+
end
|
56
|
+
|
66
57
|
# Build array of grouped values whose sort order may go back and forth, which is also sorted with key name.
|
67
58
|
# This method needs to group values with the same start because it can be changed in `Haml::AttributeBuidler#build_data_keys`.
|
68
59
|
# @param values [Array<Haml::AttributeCompiler::AttributeValue>]
|
@@ -129,7 +120,7 @@ module Haml
|
|
129
120
|
|
130
121
|
arguments = [@is_html, @attr_wrapper, @escape_attrs, @hyphenate_data_attrs]
|
131
122
|
code = "::Haml::AttributeBuilder.build_attributes"\
|
132
|
-
"(#{arguments.map
|
123
|
+
"(#{arguments.map(&method(:to_literal)).join(', ')}, { #{hash_content} })"
|
133
124
|
[:static, eval(code).to_s]
|
134
125
|
end
|
135
126
|
|
@@ -138,16 +129,16 @@ module Haml
|
|
138
129
|
# @return [String]
|
139
130
|
def merged_value(key, values)
|
140
131
|
if values.size == 1
|
141
|
-
values.first
|
132
|
+
attr_literal(values.first)
|
142
133
|
else
|
143
|
-
"::Haml::AttributeBuilder.merge_values(#{frozen_string(key)}, #{values.map(
|
134
|
+
"::Haml::AttributeBuilder.merge_values(#{frozen_string(key)}, #{values.map(&method(:attr_literal)).join(', ')})"
|
144
135
|
end
|
145
136
|
end
|
146
137
|
|
147
138
|
# @param str [String]
|
148
139
|
# @return [String]
|
149
140
|
def frozen_string(str)
|
150
|
-
"#{
|
141
|
+
"#{to_literal(str)}.freeze"
|
151
142
|
end
|
152
143
|
|
153
144
|
# Compiles attribute values for one key to Temple expression that generates ` key='value'`.
|
@@ -156,7 +147,7 @@ module Haml
|
|
156
147
|
# @param values [Array<AttributeValue>]
|
157
148
|
# @return [Array] Temple expression
|
158
149
|
def compile_attribute(key, values)
|
159
|
-
if values.all? { |v| Temple::StaticAnalyzer.static?(v
|
150
|
+
if values.all? { |v| Temple::StaticAnalyzer.static?(attr_literal(v)) }
|
160
151
|
return static_build(values)
|
161
152
|
end
|
162
153
|
|
@@ -180,7 +171,7 @@ module Haml
|
|
180
171
|
['false, nil', [:multi]],
|
181
172
|
[:else, [:multi,
|
182
173
|
[:static, " #{id_or_class}=#{@attr_wrapper}"],
|
183
|
-
[:escape, @escape_attrs, [:dynamic, var]],
|
174
|
+
[:escape, Escapable::EscapeSafeBuffer.new(@escape_attrs), [:dynamic, var]],
|
184
175
|
[:static, @attr_wrapper]],
|
185
176
|
]
|
186
177
|
],
|
@@ -200,7 +191,7 @@ module Haml
|
|
200
191
|
['false, nil', [:multi]],
|
201
192
|
[:else, [:multi,
|
202
193
|
[:static, " #{key}=#{@attr_wrapper}"],
|
203
|
-
[:escape, @escape_attrs, [:dynamic, var]],
|
194
|
+
[:escape, Escapable::EscapeSafeBuffer.new(@escape_attrs), [:dynamic, var]],
|
204
195
|
[:static, @attr_wrapper]],
|
205
196
|
]
|
206
197
|
],
|
@@ -219,5 +210,26 @@ module Haml
|
|
219
210
|
@unique_name ||= 0
|
220
211
|
"_haml_attribute_compiler#{@unique_name += 1}"
|
221
212
|
end
|
213
|
+
|
214
|
+
# @param [Haml::AttributeCompiler::AttributeValue] attr
|
215
|
+
def attr_literal(attr)
|
216
|
+
case attr.type
|
217
|
+
when :static
|
218
|
+
to_literal(attr.value)
|
219
|
+
when :dynamic
|
220
|
+
attr.value
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# For haml/haml#972
|
225
|
+
# @param [Object] value
|
226
|
+
def to_literal(value)
|
227
|
+
case value
|
228
|
+
when true, false
|
229
|
+
value.to_s
|
230
|
+
else
|
231
|
+
Haml::Util.inspect_obj(value)
|
232
|
+
end
|
233
|
+
end
|
222
234
|
end
|
223
235
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
begin
|
3
4
|
require 'ripper'
|
4
5
|
rescue LoadError
|
5
6
|
end
|
7
|
+
require 'temple/static_analyzer'
|
6
8
|
|
7
9
|
module Haml
|
8
10
|
# Haml::AttriubuteParser parses Hash literal to { String (key name) => String (value literal) }.
|
@@ -14,7 +16,7 @@ module Haml
|
|
14
16
|
TYPE = 1
|
15
17
|
TEXT = 2
|
16
18
|
|
17
|
-
IGNORED_TYPES = %i[on_sp on_ignored_nl]
|
19
|
+
IGNORED_TYPES = %i[on_sp on_ignored_nl].freeze
|
18
20
|
|
19
21
|
class << self
|
20
22
|
# @return [Boolean] - return true if AttributeParser.parse can be used.
|
@@ -98,16 +100,16 @@ module Haml
|
|
98
100
|
all_tokens = Ripper.lex(hash_literal.strip)
|
99
101
|
all_tokens = all_tokens[1...-1] || [] # strip tokens for brackets
|
100
102
|
|
101
|
-
|
103
|
+
each_balanced_tokens(all_tokens) do |tokens|
|
102
104
|
key = shift_key!(tokens)
|
103
|
-
value = tokens.map
|
105
|
+
value = tokens.map {|t| t[2] }.join.strip
|
104
106
|
block.call(key, value)
|
105
107
|
end
|
106
108
|
end
|
107
109
|
|
108
110
|
# @param [Array] tokens - Ripper tokens
|
109
111
|
# @param [Proc] block - that takes balanced Ripper tokens as arguments
|
110
|
-
def
|
112
|
+
def each_balanced_tokens(tokens, &block)
|
111
113
|
attr_tokens = []
|
112
114
|
open_tokens = Hash.new { |h, k| h[k] = 0 }
|
113
115
|
|
data/lib/haml/buffer.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Haml
|
3
4
|
# This class is used only internally. It holds the buffer of HTML that
|
4
5
|
# is eventually output as the resulting document.
|
@@ -132,7 +133,9 @@ module Haml
|
|
132
133
|
def attributes(class_id, obj_ref, *attributes_hashes)
|
133
134
|
attributes = class_id
|
134
135
|
attributes_hashes.each do |old|
|
135
|
-
|
136
|
+
result = {}
|
137
|
+
old.each { |k, v| result[k.to_s] = v }
|
138
|
+
AttributeBuilder.merge_attributes!(attributes, result)
|
136
139
|
end
|
137
140
|
AttributeBuilder.merge_attributes!(attributes, parse_object_ref(obj_ref)) if obj_ref
|
138
141
|
AttributeBuilder.build_attributes(
|
data/lib/haml/compiler.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'haml/attribute_builder'
|
3
4
|
require 'haml/attribute_compiler'
|
4
5
|
require 'haml/temple_line_counter'
|
@@ -167,7 +168,7 @@ module Haml
|
|
167
168
|
end
|
168
169
|
|
169
170
|
def compile_filter
|
170
|
-
unless filter = @filters[@node.value[:name]]
|
171
|
+
unless (filter = @filters[@node.value[:name]])
|
171
172
|
name = @node.value[:name]
|
172
173
|
if ["maruku", "textile"].include?(name)
|
173
174
|
raise Error.new(Error.message(:install_haml_contrib, name), @node.line - 1)
|
@@ -187,30 +188,28 @@ module Haml
|
|
187
188
|
|
188
189
|
if @options.html5?
|
189
190
|
'<!DOCTYPE html>'
|
190
|
-
|
191
|
-
if @
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
else
|
197
|
-
case @node.value[:type]
|
198
|
-
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
199
|
-
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
|
200
|
-
when "mobile"; '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
|
201
|
-
when "rdfa"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">'
|
202
|
-
when "basic"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
|
203
|
-
else '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
elsif @options.html4?
|
191
|
+
elsif @options.xhtml?
|
192
|
+
if @node.value[:version] == "1.1"
|
193
|
+
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
|
194
|
+
elsif @node.value[:version] == "5"
|
195
|
+
'<!DOCTYPE html>'
|
196
|
+
else
|
208
197
|
case @node.value[:type]
|
209
|
-
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD
|
210
|
-
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD
|
211
|
-
|
198
|
+
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
199
|
+
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
|
200
|
+
when "mobile"; '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
|
201
|
+
when "rdfa"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">'
|
202
|
+
when "basic"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
|
203
|
+
else '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
212
204
|
end
|
213
205
|
end
|
206
|
+
|
207
|
+
elsif @options.html4?
|
208
|
+
case @node.value[:type]
|
209
|
+
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
|
210
|
+
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
|
211
|
+
else '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
|
212
|
+
end
|
214
213
|
end
|
215
214
|
end
|
216
215
|
|
@@ -315,7 +314,7 @@ module Haml
|
|
315
314
|
|
316
315
|
case last.first
|
317
316
|
when :text
|
318
|
-
last[1].rstrip
|
317
|
+
last[1] = last[1].rstrip
|
319
318
|
if last[1].empty?
|
320
319
|
@to_merge.slice! index
|
321
320
|
rstrip_buffer! index
|
data/lib/haml/engine.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'forwardable'
|
3
4
|
|
4
5
|
require 'haml/parser'
|
@@ -51,6 +52,9 @@ module Haml
|
|
51
52
|
# see {file:REFERENCE.md#options the Haml options documentation}
|
52
53
|
# @raise [Haml::Error] if there's a Haml syntax error in the template
|
53
54
|
def initialize(template, options = {})
|
55
|
+
# Reflect changes of `Haml::Options.defaults` to `Haml::TempleEngine` options, but `#initialize_encoding`
|
56
|
+
# should be run against the arguemnt `options[:encoding]` for backward compatibility with old `Haml::Engine`.
|
57
|
+
options = Options.defaults.dup.tap { |o| o.delete(:encoding) }.merge!(options)
|
54
58
|
@options = Options.new(options)
|
55
59
|
|
56
60
|
@template = check_haml_encoding(template) do |msg, line|
|
@@ -166,8 +170,13 @@ module Haml
|
|
166
170
|
end
|
167
171
|
|
168
172
|
begin
|
169
|
-
|
170
|
-
|
173
|
+
str = @temple_engine.precompiled_with_ambles(local_names)
|
174
|
+
eval(
|
175
|
+
"Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {}; #{str}}\n",
|
176
|
+
scope,
|
177
|
+
@options.filename,
|
178
|
+
@options.line
|
179
|
+
)
|
171
180
|
rescue ::SyntaxError => e
|
172
181
|
raise SyntaxError, e.message
|
173
182
|
end
|
data/lib/haml/error.rb
CHANGED
@@ -1,32 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Haml
|
3
4
|
# An exception raised by Haml code.
|
4
5
|
class Error < StandardError
|
5
6
|
|
6
7
|
MESSAGES = {
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
8
|
+
bad_script_indent: '"%s" is indented at wrong level: expected %d, but was at %d.',
|
9
|
+
cant_run_filter: 'Can\'t run "%s" filter; you must require its dependencies first',
|
10
|
+
cant_use_tabs_and_spaces: "Indentation can't use both tabs and spaces.",
|
11
|
+
deeper_indenting: "The line was indented %d levels deeper than the previous line.",
|
12
|
+
filter_not_defined: 'Filter "%s" is not defined.',
|
13
|
+
gem_install_filter_deps: '"%s" filter\'s %s dependency missing: try installing it or adding it to your Gemfile',
|
14
|
+
illegal_element: "Illegal element: classes and ids must have values.",
|
15
|
+
illegal_nesting_content: "Illegal nesting: nesting within a tag that already has content is illegal.",
|
16
|
+
illegal_nesting_header: "Illegal nesting: nesting within a header command is illegal.",
|
17
|
+
illegal_nesting_line: "Illegal nesting: content can't be both given on the same line as %%%s and nested within it.",
|
18
|
+
illegal_nesting_plain: "Illegal nesting: nesting within plain text is illegal.",
|
19
|
+
illegal_nesting_self_closing: "Illegal nesting: nesting within a self-closing tag is illegal.",
|
20
|
+
inconsistent_indentation: "Inconsistent indentation: %s used for indentation, but the rest of the document was indented using %s.",
|
21
|
+
indenting_at_start: "Indenting at the beginning of the document is illegal.",
|
22
|
+
install_haml_contrib: 'To use the "%s" filter, please install the haml-contrib gem.',
|
23
|
+
invalid_attribute_list: 'Invalid attribute list: %s.',
|
24
|
+
invalid_filter_name: 'Invalid filter name ":%s".',
|
25
|
+
invalid_tag: 'Invalid tag: "%s".',
|
26
|
+
missing_if: 'Got "%s" with no preceding "if"',
|
27
|
+
no_ruby_code: "There's no Ruby code for %s to evaluate.",
|
28
|
+
self_closing_content: "Self-closing tags can't have content.",
|
29
|
+
unbalanced_brackets: 'Unbalanced brackets.',
|
30
|
+
no_end: <<-END
|
30
31
|
You don't need to use "- end" in Haml. Un-indent to close a block:
|
31
32
|
- if foo?
|
32
33
|
%strong Foo!
|
@@ -34,7 +35,7 @@ You don't need to use "- end" in Haml. Un-indent to close a block:
|
|
34
35
|
Not foo.
|
35
36
|
%p This line is un-indented, so it isn't part of the "if" block
|
36
37
|
END
|
37
|
-
}
|
38
|
+
}.freeze
|
38
39
|
|
39
40
|
def self.message(key, *args)
|
40
41
|
string = MESSAGES[key] or raise "[HAML BUG] No error messages for #{key}"
|
data/lib/haml/escapable.rb
CHANGED
@@ -1,32 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Haml
|
3
4
|
# Like Temple::Filters::Escapable, but with support for escaping by
|
4
5
|
# Haml::Herlpers.html_escape and Haml::Herlpers.escape_once.
|
5
6
|
class Escapable < Temple::Filter
|
7
|
+
# Special value of `flag` to ignore html_safe?
|
8
|
+
EscapeSafeBuffer = Struct.new(:value)
|
9
|
+
|
6
10
|
def initialize(*)
|
7
11
|
super
|
8
|
-
@escape_code = "::Haml::Helpers.html_escape((%s))"
|
9
|
-
@escaper = eval("proc {|v| #{@escape_code % 'v'} }")
|
10
|
-
@once_escape_code = "::Haml::Helpers.escape_once((%s))"
|
11
|
-
@once_escaper = eval("proc {|v| #{@once_escape_code % 'v'} }")
|
12
12
|
@escape = false
|
13
|
+
@escape_safe_buffer = false
|
13
14
|
end
|
14
15
|
|
15
16
|
def on_escape(flag, exp)
|
16
|
-
|
17
|
-
@
|
17
|
+
old_escape, old_escape_safe_buffer = @escape, @escape_safe_buffer
|
18
|
+
@escape_safe_buffer = flag.is_a?(EscapeSafeBuffer)
|
19
|
+
@escape = @escape_safe_buffer ? flag.value : flag
|
18
20
|
compile(exp)
|
19
21
|
ensure
|
20
|
-
@escape =
|
22
|
+
@escape, @escape_safe_buffer = old_escape, old_escape_safe_buffer
|
21
23
|
end
|
22
24
|
|
23
25
|
# The same as Haml::AttributeBuilder.build_attributes
|
24
26
|
def on_static(value)
|
25
27
|
[:static,
|
26
28
|
if @escape == :once
|
27
|
-
|
29
|
+
escape_once(value)
|
28
30
|
elsif @escape
|
29
|
-
|
31
|
+
escape(value)
|
30
32
|
else
|
31
33
|
value
|
32
34
|
end
|
@@ -37,13 +39,39 @@ module Haml
|
|
37
39
|
def on_dynamic(value)
|
38
40
|
[:dynamic,
|
39
41
|
if @escape == :once
|
40
|
-
|
42
|
+
escape_once_code(value)
|
41
43
|
elsif @escape
|
42
|
-
|
44
|
+
escape_code(value)
|
43
45
|
else
|
44
46
|
"(#{value}).to_s"
|
45
47
|
end
|
46
48
|
]
|
47
49
|
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def escape_once(value)
|
54
|
+
if @escape_safe_buffer
|
55
|
+
::Haml::Helpers.escape_once_without_haml_xss(value)
|
56
|
+
else
|
57
|
+
::Haml::Helpers.escape_once(value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def escape(value)
|
62
|
+
if @escape_safe_buffer
|
63
|
+
::Haml::Helpers.html_escape_without_haml_xss(value)
|
64
|
+
else
|
65
|
+
::Haml::Helpers.html_escape(value)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def escape_once_code(value)
|
70
|
+
"::Haml::Helpers.escape_once#{('_without_haml_xss' if @escape_safe_buffer)}((#{value}))"
|
71
|
+
end
|
72
|
+
|
73
|
+
def escape_code(value)
|
74
|
+
"::Haml::Helpers.html_escape#{('_without_haml_xss' if @escape_safe_buffer)}((#{value}))"
|
75
|
+
end
|
48
76
|
end
|
49
77
|
end
|