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.
@@ -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
- class AttributeValue < Struct.new(:type, :key, :value)
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, AttributeCompiler.runtime_build(attributes, object_ref, dynamic_attributes)]
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, AttributeCompiler.runtime_build(attributes, object_ref, dynamic_attributes)]
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 { |a| Haml::Util.inspect_obj(a) }.join(', ')}, { #{hash_content} })"
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.to_literal
132
+ attr_literal(values.first)
142
133
  else
143
- "::Haml::AttributeBuilder.merge_values(#{frozen_string(key)}, #{values.map(&:to_literal).join(', ')})"
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
- "#{Haml::Util.inspect_obj(str)}.freeze"
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.to_literal) }
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
- each_balaned_tokens(all_tokens) do |tokens|
103
+ each_balanced_tokens(all_tokens) do |tokens|
102
104
  key = shift_key!(tokens)
103
- value = tokens.map(&:last).join.strip
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 each_balaned_tokens(tokens, &block)
112
+ def each_balanced_tokens(tokens, &block)
111
113
  attr_tokens = []
112
114
  open_tokens = Hash.new { |h, k| h[k] = 0 }
113
115
 
@@ -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
- AttributeBuilder.merge_attributes!(attributes, Hash[old.map {|k, v| [k.to_s, v]}])
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(
@@ -1,4 +1,5 @@
1
- # frozen_string_literal: false
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
- else
191
- if @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
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 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">'
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
@@ -1,4 +1,5 @@
1
- # frozen_string_literal: false
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
- eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" <<
170
- @temple_engine.precompiled_with_ambles(local_names) << "}\n", scope, @options.filename, @options.line)
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
@@ -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
- :bad_script_indent => '"%s" is indented at wrong level: expected %d, but was at %d.',
8
- :cant_run_filter => 'Can\'t run "%s" filter; you must require its dependencies first',
9
- :cant_use_tabs_and_spaces => "Indentation can't use both tabs and spaces.",
10
- :deeper_indenting => "The line was indented %d levels deeper than the previous line.",
11
- :filter_not_defined => 'Filter "%s" is not defined.',
12
- :gem_install_filter_deps => '"%s" filter\'s %s dependency missing: try installing it or adding it to your Gemfile',
13
- :illegal_element => "Illegal element: classes and ids must have values.",
14
- :illegal_nesting_content => "Illegal nesting: nesting within a tag that already has content is illegal.",
15
- :illegal_nesting_header => "Illegal nesting: nesting within a header command is illegal.",
16
- :illegal_nesting_line => "Illegal nesting: content can't be both given on the same line as %%%s and nested within it.",
17
- :illegal_nesting_plain => "Illegal nesting: nesting within plain text is illegal.",
18
- :illegal_nesting_self_closing => "Illegal nesting: nesting within a self-closing tag is illegal.",
19
- :inconsistent_indentation => "Inconsistent indentation: %s used for indentation, but the rest of the document was indented using %s.",
20
- :indenting_at_start => "Indenting at the beginning of the document is illegal.",
21
- :install_haml_contrib => 'To use the "%s" filter, please install the haml-contrib gem.',
22
- :invalid_attribute_list => 'Invalid attribute list: %s.',
23
- :invalid_filter_name => 'Invalid filter name ":%s".',
24
- :invalid_tag => 'Invalid tag: "%s".',
25
- :missing_if => 'Got "%s" with no preceding "if"',
26
- :no_ruby_code => "There's no Ruby code for %s to evaluate.",
27
- :self_closing_content => "Self-closing tags can't have content.",
28
- :unbalanced_brackets => 'Unbalanced brackets.',
29
- :no_end => <<-END
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}"
@@ -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
- old = @escape
17
- @escape = flag
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 = old
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
- @once_escaper[value]
29
+ escape_once(value)
28
30
  elsif @escape
29
- @escaper[value]
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
- @once_escape_code % value
42
+ escape_once_code(value)
41
43
  elsif @escape
42
- @escape_code % value
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