haml 5.0.3 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|