haml 4.1.0.beta.1 → 5.0.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of haml might be problematic. Click here for more details.

Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +36 -6
  4. data/FAQ.md +4 -14
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +81 -48
  7. data/REFERENCE.md +86 -50
  8. data/Rakefile +28 -41
  9. data/lib/haml/attribute_builder.rb +163 -0
  10. data/lib/haml/attribute_compiler.rb +214 -0
  11. data/lib/haml/attribute_parser.rb +112 -0
  12. data/lib/haml/buffer.rb +24 -126
  13. data/lib/haml/compiler.rb +62 -281
  14. data/lib/haml/engine.rb +16 -23
  15. data/lib/haml/error.rb +2 -0
  16. data/lib/haml/escapable.rb +48 -0
  17. data/lib/haml/exec.rb +23 -12
  18. data/lib/haml/filters.rb +3 -4
  19. data/lib/haml/generator.rb +36 -0
  20. data/lib/haml/helpers.rb +61 -48
  21. data/lib/haml/helpers/action_view_extensions.rb +1 -1
  22. data/lib/haml/helpers/action_view_mods.rb +32 -50
  23. data/lib/haml/helpers/safe_erubi_template.rb +26 -0
  24. data/lib/haml/helpers/safe_erubis_template.rb +2 -0
  25. data/lib/haml/helpers/xss_mods.rb +17 -12
  26. data/lib/haml/options.rb +32 -36
  27. data/lib/haml/parser.rb +61 -38
  28. data/lib/haml/{template/plugin.rb → plugin.rb} +5 -2
  29. data/lib/haml/railtie.rb +14 -6
  30. data/lib/haml/template.rb +11 -6
  31. data/lib/haml/temple_engine.rb +119 -0
  32. data/lib/haml/temple_line_counter.rb +28 -0
  33. data/lib/haml/util.rb +17 -112
  34. data/lib/haml/version.rb +1 -1
  35. data/test/attribute_parser_test.rb +105 -0
  36. data/test/engine_test.rb +202 -106
  37. data/test/filters_test.rb +32 -19
  38. data/test/gemfiles/Gemfile.rails-4.0.x +7 -1
  39. data/test/gemfiles/Gemfile.rails-4.0.x.lock +57 -71
  40. data/test/gemfiles/Gemfile.rails-4.1.x +5 -0
  41. data/test/gemfiles/Gemfile.rails-4.2.x +5 -0
  42. data/test/gemfiles/Gemfile.rails-5.0.x +4 -0
  43. data/test/helper_test.rb +156 -109
  44. data/test/options_test.rb +21 -0
  45. data/test/parser_test.rb +49 -4
  46. data/test/results/eval_suppressed.xhtml +4 -4
  47. data/test/results/helpers.xhtml +43 -41
  48. data/test/results/helpful.xhtml +6 -3
  49. data/test/results/just_stuff.xhtml +21 -20
  50. data/test/results/list.xhtml +9 -9
  51. data/test/results/nuke_inner_whitespace.xhtml +22 -22
  52. data/test/results/nuke_outer_whitespace.xhtml +84 -92
  53. data/test/results/original_engine.xhtml +17 -17
  54. data/test/results/partial_layout.xhtml +4 -3
  55. data/test/results/partial_layout_erb.xhtml +4 -3
  56. data/test/results/partials.xhtml +11 -10
  57. data/test/results/silent_script.xhtml +63 -63
  58. data/test/results/standard.xhtml +156 -159
  59. data/test/results/tag_parsing.xhtml +19 -19
  60. data/test/results/very_basic.xhtml +2 -2
  61. data/test/results/whitespace_handling.xhtml +77 -76
  62. data/test/template_test.rb +21 -48
  63. data/test/template_test_helper.rb +38 -0
  64. data/test/templates/just_stuff.haml +1 -0
  65. data/test/templates/standard_ugly.haml +1 -0
  66. data/test/temple_line_counter_test.rb +40 -0
  67. data/test/test_helper.rb +10 -10
  68. data/test/util_test.rb +1 -48
  69. metadata +49 -35
  70. data/lib/haml/temple.rb +0 -85
  71. data/test/gemfiles/Gemfile.rails-3.2.x +0 -4
  72. data/test/templates/_av_partial_1_ugly.haml +0 -9
  73. data/test/templates/_av_partial_2_ugly.haml +0 -5
  74. data/test/templates/action_view_ugly.haml +0 -47
  75. data/test/templates/standard_ugly.haml +0 -43
@@ -7,6 +7,7 @@ require 'haml/helpers'
7
7
  require 'haml/buffer'
8
8
  require 'haml/filters'
9
9
  require 'haml/error'
10
+ require 'haml/temple_engine'
10
11
 
11
12
  module Haml
12
13
  # This is the frontend for using Haml programmatically.
@@ -35,9 +36,6 @@ module Haml
35
36
  # @return [String]
36
37
  attr_accessor :indentation
37
38
 
38
- attr_accessor :compiler
39
- attr_accessor :parser
40
-
41
39
  # Tilt currently depends on these moved methods, provide a stable API
42
40
  def_delegators :compiler, :precompiled, :precompiled_method_return_value
43
41
 
@@ -58,12 +56,13 @@ module Haml
58
56
  raise Haml::Error.new(msg, line)
59
57
  end
60
58
 
61
- initialize_encoding options[:encoding]
62
-
63
- @parser = @options.parser_class.new(@template, @options)
64
- @compiler = @options.compiler_class.new(@options)
59
+ @temple_engine = TempleEngine.new(options)
60
+ @temple_engine.compile(@template)
61
+ end
65
62
 
66
- @compiler.compile(@parser.parse)
63
+ # Deprecated API for backword compatibility
64
+ def compiler
65
+ @temple_engine
67
66
  end
68
67
 
69
68
  # Processes the template and returns the result as a string.
@@ -107,7 +106,7 @@ module Haml
107
106
  # @param block [#to_proc] A block that can be yielded to within the template
108
107
  # @return [String] The rendered template
109
108
  def render(scope = Object.new, locals = {}, &block)
110
- parent = scope.instance_variable_defined?('@haml_buffer') ? scope.instance_variable_get('@haml_buffer') : nil
109
+ parent = scope.instance_variable_defined?(:@haml_buffer) ? scope.instance_variable_get(:@haml_buffer) : nil
111
110
  buffer = Haml::Buffer.new(parent, @options.for_buffer)
112
111
 
113
112
  if scope.is_a?(Binding)
@@ -121,15 +120,15 @@ module Haml
121
120
  set_locals(locals.merge(:_hamlout => buffer, :_erbout => buffer.buffer), scope, scope_object)
122
121
 
123
122
  scope_object.extend(Haml::Helpers)
124
- scope_object.instance_variable_set(:'@haml_buffer', buffer)
123
+ scope_object.instance_variable_set(:@haml_buffer, buffer)
125
124
  begin
126
- eval(@compiler.precompiled_with_return_value, scope, @options.filename, @options.line)
125
+ eval(@temple_engine.precompiled_with_return_value, scope, @options.filename, @options.line)
127
126
  rescue ::SyntaxError => e
128
127
  raise SyntaxError, e.message
129
128
  end
130
129
  ensure
131
130
  # Get rid of the current buffer
132
- scope_object.instance_variable_set(:'@haml_buffer', buffer.upper) if buffer
131
+ scope_object.instance_variable_set(:@haml_buffer, buffer.upper) if buffer
133
132
  end
134
133
  alias_method :to_html, :render
135
134
 
@@ -166,8 +165,8 @@ module Haml
166
165
  end
167
166
 
168
167
  begin
169
- eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
170
- compiler.precompiled_with_ambles(local_names) + "}\n", scope, @options.filename, @options.line)
168
+ eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" <<
169
+ @temple_engine.precompiled_with_ambles(local_names) << "}\n", scope, @options.filename, @options.line)
171
170
  rescue ::SyntaxError => e
172
171
  raise SyntaxError, e.message
173
172
  end
@@ -177,7 +176,7 @@ module Haml
177
176
  # that renders the template and returns the result as a string.
178
177
  #
179
178
  # If `object` is a class or module,
180
- # the method will instead by defined as an instance method.
179
+ # the method will instead be defined as an instance method.
181
180
  # For example:
182
181
  #
183
182
  # t = Time.now
@@ -214,20 +213,14 @@ module Haml
214
213
  def def_method(object, name, *local_names)
215
214
  method = object.is_a?(Module) ? :module_eval : :instance_eval
216
215
 
217
- object.send(method, "def #{name}(_haml_locals = {}); #{compiler.precompiled_with_ambles(local_names)}; end",
216
+ object.send(method, "def #{name}(_haml_locals = {}); #{@temple_engine.precompiled_with_ambles(local_names)}; end",
218
217
  @options.filename, @options.line)
219
218
  end
220
219
 
221
220
  private
222
221
 
223
- def initialize_encoding(given_value)
224
- unless given_value
225
- @options.encoding = Encoding.default_internal || @template.encoding
226
- end
227
- end
228
-
229
222
  def set_locals(locals, scope, scope_object)
230
- scope_object.instance_variable_set '@_haml_locals', locals
223
+ scope_object.instance_variable_set :@_haml_locals, locals
231
224
  set_locals = locals.keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
232
225
  eval(set_locals, scope)
233
226
  end
@@ -58,4 +58,6 @@ END
58
58
  # It's not particularly interesting,
59
59
  # except in that it's a subclass of {Haml::Error}.
60
60
  class SyntaxError < Error; end
61
+
62
+ class InvalidAttributeNameError < SyntaxError; end
61
63
  end
@@ -0,0 +1,48 @@
1
+ module Haml
2
+ # Like Temple::Filters::Escapable, but with support for escaping by
3
+ # Haml::Herlpers.html_escape and Haml::Herlpers.escape_once.
4
+ class Escapable < Temple::Filter
5
+ def initialize(*)
6
+ super
7
+ @escape_code = "::Haml::Helpers.html_escape((%s))"
8
+ @escaper = eval("proc {|v| #{@escape_code % 'v'} }")
9
+ @once_escape_code = "::Haml::Helpers.escape_once((%s))"
10
+ @once_escaper = eval("proc {|v| #{@once_escape_code % 'v'} }")
11
+ @escape = false
12
+ end
13
+
14
+ def on_escape(flag, exp)
15
+ old = @escape
16
+ @escape = flag
17
+ compile(exp)
18
+ ensure
19
+ @escape = old
20
+ end
21
+
22
+ # The same as Haml::AttributeBuilder.build_attributes
23
+ def on_static(value)
24
+ [:static,
25
+ if @escape == :once
26
+ @once_escaper[value]
27
+ elsif @escape
28
+ @escaper[value]
29
+ else
30
+ value
31
+ end
32
+ ]
33
+ end
34
+
35
+ # The same as Haml::AttributeBuilder.build_attributes
36
+ def on_dynamic(value)
37
+ [:dynamic,
38
+ if @escape == :once
39
+ @once_escape_code % value
40
+ elsif @escape
41
+ @escape_code % value
42
+ else
43
+ "(#{value}).to_s"
44
+ end
45
+ ]
46
+ end
47
+ end
48
+ end
@@ -211,11 +211,6 @@ END
211
211
  @options[:output] = StringIO.new
212
212
  end
213
213
 
214
- opts.on('-t', '--style NAME',
215
- 'Output style. Can be indented (default) or ugly.') do |name|
216
- @options[:for_engine][:ugly] = true if name.to_sym == :ugly
217
- end
218
-
219
214
  opts.on('-f', '--format NAME',
220
215
  'Output format. Can be html5 (default), xhtml, or html4.') do |name|
221
216
  @options[:for_engine][:format] = name.to_sym
@@ -270,7 +265,7 @@ END
270
265
  Encoding.default_internal = internal if internal && !internal.empty?
271
266
  end
272
267
 
273
- opts.on('-d', '--debug', "Print out the precompiled Ruby source.") do
268
+ opts.on('-d', '--debug', "Print out the precompiled Ruby source, and show syntax errors in the Ruby code.") do
274
269
  @options[:debug] = true
275
270
  end
276
271
 
@@ -296,20 +291,28 @@ END
296
291
 
297
292
  begin
298
293
 
299
- engine = ::Haml::Engine.new(template, @options[:for_engine])
300
- if @options[:check_syntax]
301
- puts "Syntax OK"
294
+ if @options[:parse]
295
+ parser = ::Haml::Parser.new(template, ::Haml::Options.new(@options))
296
+ pp parser.parse
302
297
  return
303
298
  end
304
299
 
305
- if @options[:parse]
306
- pp engine.parser.root
300
+ engine = ::Haml::Engine.new(template, @options[:for_engine])
301
+
302
+ if @options[:check_syntax]
303
+ puts "Syntax OK"
307
304
  return
308
305
  end
309
306
 
310
307
  if @options[:debug]
311
308
  puts engine.precompiled
312
- puts '=' * 100
309
+ error = validate_ruby(engine.precompiled)
310
+ if error
311
+ puts '=' * 100
312
+ puts error.message.split("\n")[0]
313
+ exit 1
314
+ end
315
+ return
313
316
  end
314
317
 
315
318
  result = engine.to_html
@@ -326,6 +329,14 @@ END
326
329
  output.write(result)
327
330
  output.close() if output.is_a? File
328
331
  end
332
+
333
+ def validate_ruby(code)
334
+ begin
335
+ eval("BEGIN {return nil}; #{code}")
336
+ rescue ::SyntaxError # Not to be confused with Haml::SyntaxError
337
+ $!
338
+ end
339
+ end
329
340
  end
330
341
  end
331
342
  end
@@ -59,7 +59,7 @@ module Haml
59
59
  end
60
60
 
61
61
  # Removes a filter from Haml. If the filter was removed, it returns
62
- # the that was remove Module upon success, or nil on failure. If you try
62
+ # the Module that was removed upon success, or nil on failure. If you try
63
63
  # to redefine a filter, Haml will raise an error. Use this method first to
64
64
  # explicitly remove the filter before redefining it.
65
65
  # @return Module The filter module that has been removed
@@ -163,7 +163,7 @@ module Haml
163
163
  if contains_interpolation?(text)
164
164
  return if options[:suppress_eval]
165
165
 
166
- text = unescape_interpolation(text).gsub(/(\\+)n/) do |s|
166
+ text = unescape_interpolation(text, options[:escape_html]).gsub(/(\\+)n/) do |s|
167
167
  escapes = $1.size
168
168
  next s if escapes % 2 == 0
169
169
  "#{'\\' * (escapes - 1)}\n"
@@ -183,8 +183,7 @@ RUBY
183
183
 
184
184
  rendered = Haml::Helpers::find_and_preserve(filter.render_with_options(text, compiler.options), compiler.options[:preserve])
185
185
  rendered.rstrip!
186
- rendered.gsub!("\n", "\n#{' ' * @output_tabs}") unless options[:ugly]
187
- push_text(rendered)
186
+ push_text("#{rendered}\n")
188
187
  end
189
188
  end
190
189
  end
@@ -0,0 +1,36 @@
1
+ module Haml
2
+ # Ruby code generator, which is a limited version of Temple::Generator.
3
+ # Limit methods since Haml doesn't need most of them.
4
+ class Generator
5
+ include Temple::Mixins::CompiledDispatcher
6
+ include Temple::Mixins::Options
7
+
8
+ define_options freeze_static: RUBY_VERSION >= '2.1'
9
+
10
+ def call(exp)
11
+ compile(exp)
12
+ end
13
+
14
+ def on_multi(*exp)
15
+ exp.map { |e| compile(e) }.join('; ')
16
+ end
17
+
18
+ def on_static(text)
19
+ concat(options[:freeze_static] ? "#{Util.inspect_obj(text)}.freeze" : Util.inspect_obj(text))
20
+ end
21
+
22
+ def on_dynamic(code)
23
+ concat(code)
24
+ end
25
+
26
+ def on_code(exp)
27
+ exp
28
+ end
29
+
30
+ private
31
+
32
+ def concat(str)
33
+ "_hamlout.buffer << (#{str});"
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,5 @@
1
+ require 'erb'
2
+
1
3
  module Haml
2
4
  # This module contains various helpful methods to make it easier to do various tasks.
3
5
  # {Haml::Helpers} is automatically included in the context
@@ -106,7 +108,11 @@ MESSAGE
106
108
  # @yield The block within which to escape newlines
107
109
  def find_and_preserve(input = nil, tags = haml_buffer.options[:preserve], &block)
108
110
  return find_and_preserve(capture_haml(&block), input || tags) if block
109
- re = /<(#{tags.map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im
111
+ tags = tags.each_with_object('') do |t, s|
112
+ s << '|' unless s.empty?
113
+ s << Regexp.escape(t)
114
+ end
115
+ re = /<(#{tags})([^>]*)>(.*?)(<\/\1>)/im
110
116
  input.to_s.gsub(re) do |s|
111
117
  s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
112
118
  "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
@@ -193,19 +199,20 @@ MESSAGE
193
199
  # @yield [item] A block which contains Haml code that goes within list items
194
200
  # @yieldparam item An element of `enum`
195
201
  def list_of(enum, opts={}, &block)
196
- opts_attributes = opts.empty? ? "" : " ".<<(opts.map{|k,v| "#{k}='#{v}'" }.join(" "))
197
- enum.collect do |i|
202
+ opts_attributes = opts.each_with_object('') {|(k, v), s| s << " #{k}='#{v}'"}
203
+ enum.each_with_object('') do |i, ret|
198
204
  result = capture_haml(i, &block)
199
205
 
200
- result = if result.count("\n") > 1
206
+ if result.count("\n") > 1
201
207
  result.gsub!("\n", "\n ")
202
- "\n #{result.strip}\n"
208
+ result = "\n #{result.strip!}\n"
203
209
  else
204
- result.strip
210
+ result.strip!
205
211
  end
206
212
 
207
- %Q!<li#{opts_attributes}>#{result}</li>!
208
- end.join("\n")
213
+ ret << "\n" unless ret.empty?
214
+ ret << %Q!<li#{opts_attributes}>#{result}</li>!
215
+ end
209
216
  end
210
217
 
211
218
  # Returns a hash containing default assignments for the `xmlns`, `lang`, and `xml:lang`
@@ -379,8 +386,7 @@ MESSAGE
379
386
  captured = (value.is_a?(String) ? value : nil)
380
387
  end
381
388
 
382
- return nil if captured.nil?
383
- return (haml_buffer.options[:ugly] ? captured : prettify(captured))
389
+ captured
384
390
  end
385
391
  ensure
386
392
  haml_buffer.capture_position = nil
@@ -390,13 +396,34 @@ MESSAGE
390
396
  #
391
397
  # @param text [#to_s] The text to output
392
398
  def haml_concat(text = "")
393
- if haml_buffer.options[:ugly] || haml_indent == 0
394
- haml_buffer.buffer << "#{text}\n"
399
+ haml_internal_concat text
400
+ ErrorReturn.new("haml_concat")
401
+ end
402
+
403
+ # Internal method to write directly to the buffer with control of
404
+ # whether the first line should be indented, and if there should be a
405
+ # final newline.
406
+ #
407
+ # Lines added will have the proper indentation. This can be controlled
408
+ # for the first line.
409
+ #
410
+ # Used by #haml_concat and #haml_tag.
411
+ #
412
+ # @param text [#to_s] The text to output
413
+ # @param newline [Boolean] Whether to add a newline after the text
414
+ # @param indent [Boolean] Whether to add indentation to the first line
415
+ def haml_internal_concat(text = "", newline = true, indent = true)
416
+ if haml_buffer.tabulation == 0
417
+ haml_buffer.buffer << "#{text}#{"\n" if newline}"
395
418
  else
396
- haml_buffer.buffer << %[#{haml_indent}#{text.to_s.gsub("\n", "\n#{haml_indent}")}\n]
419
+ haml_buffer.buffer << %[#{haml_indent if indent}#{text.to_s.gsub("\n", "\n#{haml_indent}")}#{"\n" if newline}]
397
420
  end
398
- ErrorReturn.new("haml_concat")
399
421
  end
422
+ private :haml_internal_concat
423
+
424
+ # Allows writing raw content. `haml_internal_concat_raw` isn't
425
+ # effected by XSS mods. Used by #haml_tag to write the actual tags.
426
+ alias :haml_internal_concat_raw :haml_internal_concat
400
427
 
401
428
  # @return [String] The indentation string for the current line
402
429
  def haml_indent
@@ -470,14 +497,14 @@ MESSAGE
470
497
  attrs.keys.each {|key| attrs[key.to_s] = attrs.delete(key)} unless attrs.empty?
471
498
  name, attrs = merge_name_and_attributes(name.to_s, attrs)
472
499
 
473
- attributes = Haml::Compiler.build_attributes(haml_buffer.html?,
500
+ attributes = Haml::AttributeBuilder.build_attributes(haml_buffer.html?,
474
501
  haml_buffer.options[:attr_wrapper],
475
502
  haml_buffer.options[:escape_attrs],
476
503
  haml_buffer.options[:hyphenate_data_attrs],
477
504
  attrs)
478
505
 
479
506
  if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
480
- haml_concat "<#{name}#{attributes}#{' /' if haml_buffer.options[:format] == :xhtml}>"
507
+ haml_internal_concat_raw "<#{name}#{attributes}#{' /' if haml_buffer.options[:format] == :xhtml}>"
481
508
  return ret
482
509
  end
483
510
 
@@ -487,17 +514,19 @@ MESSAGE
487
514
  end
488
515
 
489
516
  tag = "<#{name}#{attributes}>"
517
+ end_tag = "</#{name}>"
490
518
  if block.nil?
491
519
  text = text.to_s
492
520
  if text.include?("\n")
493
- haml_concat tag
521
+ haml_internal_concat_raw tag
494
522
  tab_up
495
- haml_concat text
523
+ haml_internal_concat text
496
524
  tab_down
497
- haml_concat "</#{name}>"
525
+ haml_internal_concat_raw end_tag
498
526
  else
499
- tag << "#{text}</#{name}>"
500
- haml_concat tag
527
+ haml_internal_concat_raw tag, false
528
+ haml_internal_concat text, false, false
529
+ haml_internal_concat_raw end_tag, true, false
501
530
  end
502
531
  return ret
503
532
  end
@@ -507,22 +536,23 @@ MESSAGE
507
536
  end
508
537
 
509
538
  if flags.include?(:<)
510
- tag << "#{capture_haml(&block).strip}</#{name}>"
511
- haml_concat tag
539
+ haml_internal_concat_raw tag, false
540
+ haml_internal_concat "#{capture_haml(&block).strip}", false, false
541
+ haml_internal_concat_raw end_tag, true, false
512
542
  return ret
513
543
  end
514
544
 
515
- haml_concat tag
545
+ haml_internal_concat_raw tag
516
546
  tab_up
517
547
  block.call
518
548
  tab_down
519
- haml_concat "</#{name}>"
549
+ haml_internal_concat_raw end_tag
520
550
 
521
551
  ret
522
552
  end
523
553
 
524
554
  # Conditionally wrap a block in an element. If `condition` is `true` then
525
- # this method renders the tag described by the argumants in `tag` (using
555
+ # this method renders the tag described by the arguments in `tag` (using
526
556
  # \{#haml_tag}) with the given block inside, otherwise it just renders the block.
527
557
  #
528
558
  # For example,
@@ -565,9 +595,9 @@ MESSAGE
565
595
  end
566
596
 
567
597
  # Characters that need to be escaped to HTML entities from user input
568
- HTML_ESCAPE = { '&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;', "'" => '&#039;' }
598
+ HTML_ESCAPE = { '&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;', "'" => '&#39;' }
569
599
 
570
- HTML_ESCAPE_REGEX = /[\"><&]/
600
+ HTML_ESCAPE_REGEX = /['"><&]/
571
601
 
572
602
  # Returns a copy of `text` with ampersands, angle brackets and quotes
573
603
  # escaped into HTML entities.
@@ -579,11 +609,10 @@ MESSAGE
579
609
  # @param text [String] The string to sanitize
580
610
  # @return [String] The sanitized string
581
611
  def html_escape(text)
582
- text = text.to_s
583
- text.gsub(HTML_ESCAPE_REGEX, HTML_ESCAPE)
612
+ ERB::Util.html_escape(text)
584
613
  end
585
614
 
586
- HTML_ESCAPE_ONCE_REGEX = /[\"><]|&(?!(?:[a-zA-Z]+|#(?:\d+|[xX][0-9a-fA-F]+));)/
615
+ HTML_ESCAPE_ONCE_REGEX = /['"><]|&(?!(?:[a-zA-Z]+|#(?:\d+|[xX][0-9a-fA-F]+));)/
587
616
 
588
617
  # Escapes HTML entities in `text`, but without escaping an ampersand
589
618
  # that is already part of an escaped entity.
@@ -622,7 +651,7 @@ MESSAGE
622
651
  # skip merging if no ids or classes found in name
623
652
  return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/
624
653
 
625
- return $1 || "div", Buffer.merge_attrs(
654
+ return $1 || "div", AttributeBuilder.merge_attributes!(
626
655
  Haml::Parser.parse_class_and_id($2), attributes_hash)
627
656
  end
628
657
 
@@ -659,22 +688,6 @@ MESSAGE
659
688
  _erbout = _erbout = _hamlout.buffer
660
689
  proc { |*args| proc.call(*args) }
661
690
  end
662
-
663
- def prettify(text)
664
- text = text.split(/^/)
665
- text.delete('')
666
-
667
- min_tabs = nil
668
- text.each do |line|
669
- tabs = line.index(/[^ ]/) || line.length
670
- min_tabs ||= tabs
671
- min_tabs = min_tabs > tabs ? tabs : min_tabs
672
- end
673
-
674
- text.map do |line|
675
- line.slice(min_tabs, line.length)
676
- end.join
677
- end
678
691
  end
679
692
  end
680
693