haml 4.0.7 → 5.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +18 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +54 -0
  5. data/.yardopts +1 -1
  6. data/CHANGELOG.md +96 -4
  7. data/FAQ.md +4 -14
  8. data/Gemfile +19 -0
  9. data/MIT-LICENSE +1 -1
  10. data/README.md +80 -42
  11. data/REFERENCE.md +116 -64
  12. data/Rakefile +46 -54
  13. data/TODO +24 -0
  14. data/benchmark.rb +66 -0
  15. data/haml.gemspec +38 -0
  16. data/lib/haml/.gitattributes +1 -0
  17. data/lib/haml/attribute_builder.rb +163 -0
  18. data/lib/haml/attribute_compiler.rb +223 -0
  19. data/lib/haml/attribute_parser.rb +148 -0
  20. data/lib/haml/buffer.rb +22 -132
  21. data/lib/haml/compiler.rb +89 -298
  22. data/lib/haml/engine.rb +25 -41
  23. data/lib/haml/error.rb +3 -0
  24. data/lib/haml/escapable.rb +49 -0
  25. data/lib/haml/exec.rb +38 -19
  26. data/lib/haml/filters.rb +18 -24
  27. data/lib/haml/generator.rb +41 -0
  28. data/lib/haml/helpers/action_view_extensions.rb +3 -2
  29. data/lib/haml/helpers/action_view_mods.rb +42 -60
  30. data/lib/haml/helpers/action_view_xss_mods.rb +1 -0
  31. data/lib/haml/helpers/safe_erubi_template.rb +19 -0
  32. data/lib/haml/helpers/safe_erubis_template.rb +4 -1
  33. data/lib/haml/helpers/xss_mods.rb +18 -12
  34. data/lib/haml/helpers.rb +132 -89
  35. data/lib/haml/options.rb +41 -47
  36. data/lib/haml/parser.rb +278 -216
  37. data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
  38. data/lib/haml/railtie.rb +38 -12
  39. data/lib/haml/sass_rails_filter.rb +17 -4
  40. data/lib/haml/template/options.rb +12 -2
  41. data/lib/haml/template.rb +12 -6
  42. data/lib/haml/temple_engine.rb +121 -0
  43. data/lib/haml/temple_line_counter.rb +29 -0
  44. data/lib/haml/util.rb +80 -199
  45. data/lib/haml/version.rb +2 -1
  46. data/lib/haml.rb +1 -0
  47. data/yard/default/.gitignore +1 -0
  48. data/yard/default/fulldoc/html/css/common.sass +15 -0
  49. data/yard/default/layout/html/footer.erb +12 -0
  50. metadata +50 -111
  51. data/test/engine_test.rb +0 -2013
  52. data/test/erb/_av_partial_1.erb +0 -12
  53. data/test/erb/_av_partial_2.erb +0 -8
  54. data/test/erb/action_view.erb +0 -62
  55. data/test/erb/standard.erb +0 -55
  56. data/test/filters_test.rb +0 -254
  57. data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
  58. data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
  59. data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
  60. data/test/gemfiles/Gemfile.rails-4.0.x +0 -5
  61. data/test/haml-spec/LICENSE +0 -14
  62. data/test/haml-spec/README.md +0 -106
  63. data/test/haml-spec/lua_haml_spec.lua +0 -38
  64. data/test/haml-spec/perl_haml_test.pl +0 -81
  65. data/test/haml-spec/ruby_haml_test.rb +0 -23
  66. data/test/haml-spec/tests.json +0 -660
  67. data/test/helper_test.rb +0 -583
  68. data/test/markaby/standard.mab +0 -52
  69. data/test/mocks/article.rb +0 -6
  70. data/test/parser_test.rb +0 -105
  71. data/test/results/content_for_layout.xhtml +0 -12
  72. data/test/results/eval_suppressed.xhtml +0 -9
  73. data/test/results/helpers.xhtml +0 -70
  74. data/test/results/helpful.xhtml +0 -10
  75. data/test/results/just_stuff.xhtml +0 -70
  76. data/test/results/list.xhtml +0 -12
  77. data/test/results/nuke_inner_whitespace.xhtml +0 -40
  78. data/test/results/nuke_outer_whitespace.xhtml +0 -148
  79. data/test/results/original_engine.xhtml +0 -20
  80. data/test/results/partial_layout.xhtml +0 -5
  81. data/test/results/partial_layout_erb.xhtml +0 -5
  82. data/test/results/partials.xhtml +0 -21
  83. data/test/results/render_layout.xhtml +0 -3
  84. data/test/results/silent_script.xhtml +0 -74
  85. data/test/results/standard.xhtml +0 -162
  86. data/test/results/tag_parsing.xhtml +0 -23
  87. data/test/results/very_basic.xhtml +0 -5
  88. data/test/results/whitespace_handling.xhtml +0 -90
  89. data/test/template_test.rb +0 -354
  90. data/test/templates/_av_partial_1.haml +0 -9
  91. data/test/templates/_av_partial_1_ugly.haml +0 -9
  92. data/test/templates/_av_partial_2.haml +0 -5
  93. data/test/templates/_av_partial_2_ugly.haml +0 -5
  94. data/test/templates/_layout.erb +0 -3
  95. data/test/templates/_layout_for_partial.haml +0 -3
  96. data/test/templates/_partial.haml +0 -8
  97. data/test/templates/_text_area.haml +0 -3
  98. data/test/templates/_text_area_helper.html.haml +0 -4
  99. data/test/templates/action_view.haml +0 -47
  100. data/test/templates/action_view_ugly.haml +0 -47
  101. data/test/templates/breakage.haml +0 -8
  102. data/test/templates/content_for_layout.haml +0 -8
  103. data/test/templates/eval_suppressed.haml +0 -11
  104. data/test/templates/helpers.haml +0 -55
  105. data/test/templates/helpful.haml +0 -11
  106. data/test/templates/just_stuff.haml +0 -85
  107. data/test/templates/list.haml +0 -12
  108. data/test/templates/nuke_inner_whitespace.haml +0 -32
  109. data/test/templates/nuke_outer_whitespace.haml +0 -144
  110. data/test/templates/original_engine.haml +0 -17
  111. data/test/templates/partial_layout.haml +0 -3
  112. data/test/templates/partial_layout_erb.erb +0 -4
  113. data/test/templates/partialize.haml +0 -1
  114. data/test/templates/partials.haml +0 -12
  115. data/test/templates/render_layout.haml +0 -2
  116. data/test/templates/silent_script.haml +0 -45
  117. data/test/templates/standard.haml +0 -43
  118. data/test/templates/standard_ugly.haml +0 -43
  119. data/test/templates/tag_parsing.haml +0 -21
  120. data/test/templates/very_basic.haml +0 -4
  121. data/test/templates/whitespace_handling.haml +0 -87
  122. data/test/test_helper.rb +0 -81
  123. data/test/util_test.rb +0 -63
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+ require 'action_view'
3
+
1
4
  module Haml
2
5
 
3
6
  class ErubisTemplateHandler < ActionView::Template::Handlers::Erubis
@@ -26,4 +29,4 @@ module Haml
26
29
  [super, '@output_buffer.to_s'].join("\n")
27
30
  end
28
31
  end
29
- end
32
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Haml
2
3
  module Helpers
3
4
  # This module overrides Haml helpers to work properly
@@ -7,8 +8,8 @@ module Haml
7
8
  module XssMods
8
9
  def self.included(base)
9
10
  %w[html_escape find_and_preserve preserve list_of surround
10
- precede succeed capture_haml haml_concat haml_indent
11
- haml_tag escape_once].each do |name|
11
+ precede succeed capture_haml haml_concat haml_internal_concat haml_indent
12
+ escape_once].each do |name|
12
13
  base.send(:alias_method, "#{name}_without_haml_xss", name)
13
14
  base.send(:alias_method, name, "#{name}_with_haml_xss")
14
15
  end
@@ -61,24 +62,29 @@ module Haml
61
62
  Haml::Util.html_safe(capture_haml_without_haml_xss(*args, &block))
62
63
  end
63
64
 
64
- # Input is escaped
65
+ # Input will be escaped unless this is in a `with_raw_haml_concat`
66
+ # block. See #Haml::Helpers::ActionViewExtensions#with_raw_haml_concat.
65
67
  def haml_concat_with_haml_xss(text = "")
66
- raw = instance_variable_defined?('@_haml_concat_raw') ? @_haml_concat_raw : false
67
- haml_concat_without_haml_xss(raw ? text : haml_xss_html_escape(text))
68
+ raw = instance_variable_defined?(:@_haml_concat_raw) ? @_haml_concat_raw : false
69
+ if raw
70
+ haml_internal_concat_raw text
71
+ else
72
+ haml_internal_concat text
73
+ end
74
+ ErrorReturn.new("haml_concat")
68
75
  end
69
76
 
77
+ # Input is escaped
78
+ def haml_internal_concat_with_haml_xss(text="", newline=true, indent=true)
79
+ haml_internal_concat_without_haml_xss(haml_xss_html_escape(text), newline, indent)
80
+ end
81
+ private :haml_internal_concat_with_haml_xss
82
+
70
83
  # Output is always HTML safe
71
84
  def haml_indent_with_haml_xss
72
85
  Haml::Util.html_safe(haml_indent_without_haml_xss)
73
86
  end
74
87
 
75
- # Input is escaped, haml_concat'ed output is always HTML safe
76
- def haml_tag_with_haml_xss(name, *rest, &block)
77
- name = haml_xss_html_escape(name.to_s)
78
- rest.unshift(haml_xss_html_escape(rest.shift.to_s)) unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
79
- with_raw_haml_concat {haml_tag_without_haml_xss(name, *rest, &block)}
80
- end
81
-
82
88
  # Output is always HTML safe
83
89
  def escape_once_with_haml_xss(*args)
84
90
  Haml::Util.html_safe(escape_once_without_haml_xss(*args))
data/lib/haml/helpers.rb CHANGED
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: false
2
+ require 'erb'
3
+
1
4
  module Haml
2
5
  # This module contains various helpful methods to make it easier to do various tasks.
3
6
  # {Haml::Helpers} is automatically included in the context
@@ -106,7 +109,11 @@ MESSAGE
106
109
  # @yield The block within which to escape newlines
107
110
  def find_and_preserve(input = nil, tags = haml_buffer.options[:preserve], &block)
108
111
  return find_and_preserve(capture_haml(&block), input || tags) if block
109
- re = /<(#{tags.map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im
112
+ tags = tags.each_with_object('') do |t, s|
113
+ s << '|' unless s.empty?
114
+ s << Regexp.escape(t)
115
+ end
116
+ re = /<(#{tags})([^>]*)>(.*?)(<\/\1>)/im
110
117
  input.to_s.gsub(re) do |s|
111
118
  s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
112
119
  "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
@@ -117,17 +124,20 @@ MESSAGE
117
124
  # HTML entities so they'll render correctly in
118
125
  # whitespace-sensitive tags without screwing up the indentation.
119
126
  #
120
- # @overload perserve(input)
127
+ # @overload preserve(input)
121
128
  # Escapes newlines within a string.
122
129
  #
123
130
  # @param input [String] The string within which to escape all newlines
124
- # @overload perserve
131
+ # @overload preserve
125
132
  # Escapes newlines within a block of Haml code.
126
133
  #
127
134
  # @yield The block within which to escape newlines
128
135
  def preserve(input = nil, &block)
129
136
  return preserve(capture_haml(&block)) if block
130
- input.to_s.chomp("\n").gsub(/\n/, '&#x000A;').gsub(/\r/, '')
137
+ s = input.to_s.chomp("\n")
138
+ s.gsub!(/\n/, '&#x000A;')
139
+ s.delete!("\r")
140
+ s
131
141
  end
132
142
  alias_method :flatten, :preserve
133
143
 
@@ -190,20 +200,20 @@ MESSAGE
190
200
  # @yield [item] A block which contains Haml code that goes within list items
191
201
  # @yieldparam item An element of `enum`
192
202
  def list_of(enum, opts={}, &block)
193
- opts_attributes = opts.empty? ? "" : " ".<<(opts.map{|k,v| "#{k}='#{v}'" }.join(" "))
194
- to_return = enum.collect do |i|
203
+ opts_attributes = opts.each_with_object('') {|(k, v), s| s << " #{k}='#{v}'"}
204
+ enum.each_with_object('') do |i, ret|
195
205
  result = capture_haml(i, &block)
196
206
 
197
207
  if result.count("\n") > 1
198
- result = result.gsub("\n", "\n ")
208
+ result.gsub!("\n", "\n ")
199
209
  result = "\n #{result.strip}\n"
200
210
  else
201
- result = result.strip
211
+ result.strip!
202
212
  end
203
213
 
204
- %Q!<li#{opts_attributes}>#{result}</li>!
214
+ ret << "\n" unless ret.empty?
215
+ ret << %Q!<li#{opts_attributes}>#{result}</li>!
205
216
  end
206
- to_return.join("\n")
207
217
  end
208
218
 
209
219
  # Returns a hash containing default assignments for the `xmlns`, `lang`, and `xml:lang`
@@ -219,7 +229,11 @@ MESSAGE
219
229
  # @param lang [String] The value of `xml:lang` and `lang`
220
230
  # @return [{#to_s => String}] The attribute hash
221
231
  def html_attrs(lang = 'en-US')
222
- {:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
232
+ if haml_buffer.options[:format] == :xhtml
233
+ {:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
234
+ else
235
+ {:lang => lang}
236
+ end
223
237
  end
224
238
 
225
239
  # Increments the number of tabs the buffer automatically adds
@@ -370,12 +384,10 @@ MESSAGE
370
384
  captured = haml_buffer.buffer.slice!(position..-1)
371
385
 
372
386
  if captured == '' and value != haml_buffer.buffer
373
- captured = (value.is_a?(String) ? value : nil)
387
+ captured = (value.is_a?(String) ? value : nil)
374
388
  end
375
389
 
376
- return nil if captured.nil?
377
- return (haml_buffer.options[:ugly] ? captured : prettify(captured))
378
-
390
+ captured
379
391
  end
380
392
  ensure
381
393
  haml_buffer.capture_position = nil
@@ -385,14 +397,34 @@ MESSAGE
385
397
  #
386
398
  # @param text [#to_s] The text to output
387
399
  def haml_concat(text = "")
388
- unless haml_buffer.options[:ugly] || haml_indent == 0
389
- haml_buffer.buffer << haml_indent <<
390
- text.to_s.gsub("\n", "\n" + haml_indent) << "\n"
400
+ haml_internal_concat text
401
+ ErrorReturn.new("haml_concat")
402
+ end
403
+
404
+ # Internal method to write directly to the buffer with control of
405
+ # whether the first line should be indented, and if there should be a
406
+ # final newline.
407
+ #
408
+ # Lines added will have the proper indentation. This can be controlled
409
+ # for the first line.
410
+ #
411
+ # Used by #haml_concat and #haml_tag.
412
+ #
413
+ # @param text [#to_s] The text to output
414
+ # @param newline [Boolean] Whether to add a newline after the text
415
+ # @param indent [Boolean] Whether to add indentation to the first line
416
+ def haml_internal_concat(text = "", newline = true, indent = true)
417
+ if haml_buffer.tabulation == 0
418
+ haml_buffer.buffer << "#{text}#{"\n" if newline}"
391
419
  else
392
- haml_buffer.buffer << text.to_s << "\n"
420
+ haml_buffer.buffer << %[#{haml_indent if indent}#{text.to_s.gsub("\n", "\n#{haml_indent}")}#{"\n" if newline}]
393
421
  end
394
- ErrorReturn.new("haml_concat")
395
422
  end
423
+ private :haml_internal_concat
424
+
425
+ # Allows writing raw content. `haml_internal_concat_raw` isn't
426
+ # effected by XSS mods. Used by #haml_tag to write the actual tags.
427
+ alias :haml_internal_concat_raw :haml_internal_concat
396
428
 
397
429
  # @return [String] The indentation string for the current line
398
430
  def haml_indent
@@ -466,14 +498,14 @@ MESSAGE
466
498
  attrs.keys.each {|key| attrs[key.to_s] = attrs.delete(key)} unless attrs.empty?
467
499
  name, attrs = merge_name_and_attributes(name.to_s, attrs)
468
500
 
469
- attributes = Haml::Compiler.build_attributes(haml_buffer.html?,
501
+ attributes = Haml::AttributeBuilder.build_attributes(haml_buffer.html?,
470
502
  haml_buffer.options[:attr_wrapper],
471
503
  haml_buffer.options[:escape_attrs],
472
504
  haml_buffer.options[:hyphenate_data_attrs],
473
505
  attrs)
474
506
 
475
507
  if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
476
- haml_concat "<#{name}#{attributes} />"
508
+ haml_internal_concat_raw "<#{name}#{attributes}#{' /' if haml_buffer.options[:format] == :xhtml}>"
477
509
  return ret
478
510
  end
479
511
 
@@ -483,17 +515,19 @@ MESSAGE
483
515
  end
484
516
 
485
517
  tag = "<#{name}#{attributes}>"
518
+ end_tag = "</#{name}>"
486
519
  if block.nil?
487
520
  text = text.to_s
488
521
  if text.include?("\n")
489
- haml_concat tag
522
+ haml_internal_concat_raw tag
490
523
  tab_up
491
- haml_concat text
524
+ haml_internal_concat text
492
525
  tab_down
493
- haml_concat "</#{name}>"
526
+ haml_internal_concat_raw end_tag
494
527
  else
495
- tag << text << "</#{name}>"
496
- haml_concat tag
528
+ haml_internal_concat_raw tag, false
529
+ haml_internal_concat text, false, false
530
+ haml_internal_concat_raw end_tag, true, false
497
531
  end
498
532
  return ret
499
533
  end
@@ -503,67 +537,92 @@ MESSAGE
503
537
  end
504
538
 
505
539
  if flags.include?(:<)
506
- tag << capture_haml(&block).strip << "</#{name}>"
507
- haml_concat tag
540
+ haml_internal_concat_raw tag, false
541
+ haml_internal_concat "#{capture_haml(&block).strip}", false, false
542
+ haml_internal_concat_raw end_tag, true, false
508
543
  return ret
509
544
  end
510
545
 
511
- haml_concat tag
546
+ haml_internal_concat_raw tag
512
547
  tab_up
513
548
  block.call
514
549
  tab_down
515
- haml_concat "</#{name}>"
550
+ haml_internal_concat_raw end_tag
516
551
 
517
552
  ret
518
553
  end
519
554
 
520
- # Characters that need to be escaped to HTML entities from user input
521
- HTML_ESCAPE = { '&'=>'&amp;', '<'=>'&lt;', '>'=>'&gt;', '"'=>'&quot;', "'"=>'&#039;', }
555
+ # Conditionally wrap a block in an element. If `condition` is `true` then
556
+ # this method renders the tag described by the arguments in `tag` (using
557
+ # \{#haml_tag}) with the given block inside, otherwise it just renders the block.
558
+ #
559
+ # For example,
560
+ #
561
+ # - haml_tag_if important, '.important' do
562
+ # %p
563
+ # A (possibly) important paragraph.
564
+ #
565
+ # will produce
566
+ #
567
+ # <div class='important'>
568
+ # <p>
569
+ # A (possibly) important paragraph.
570
+ # </p>
571
+ # </div>
572
+ #
573
+ # if `important` is truthy, and just
574
+ #
575
+ # <p>
576
+ # A (possibly) important paragraph.
577
+ # </p>
578
+ #
579
+ # otherwise.
580
+ #
581
+ # Like \{#haml_tag}, `haml_tag_if` outputs directly to the buffer and its
582
+ # return value should not be used. Use \{#capture_haml} if you need to use
583
+ # its results as a string.
584
+ #
585
+ # @param condition The condition to test to determine whether to render
586
+ # the enclosing tag
587
+ # @param tag Definition of the enclosing tag. See \{#haml_tag} for details
588
+ # (specifically the form that takes a block)
589
+ def haml_tag_if(condition, *tag)
590
+ if condition
591
+ haml_tag(*tag){ yield }
592
+ else
593
+ yield
594
+ end
595
+ ErrorReturn.new("haml_tag_if")
596
+ end
522
597
 
523
- HTML_ESCAPE_REGEX = /[\"><&]/
598
+ # Characters that need to be escaped to HTML entities from user input
599
+ HTML_ESCAPE = { '&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;', "'" => '&#39;' }
524
600
 
525
- if RUBY_VERSION >= '1.9'
526
- # Include docs here so they are picked up by Yard
601
+ HTML_ESCAPE_REGEX = /['"><&]/
527
602
 
528
- # Returns a copy of `text` with ampersands, angle brackets and quotes
529
- # escaped into HTML entities.
530
- #
531
- # Note that if ActionView is loaded and XSS protection is enabled
532
- # (as is the default for Rails 3.0+, and optional for version 2.3.5+),
533
- # this won't escape text declared as "safe".
534
- #
535
- # @param text [String] The string to sanitize
536
- # @return [String] The sanitized string
537
- def html_escape(text)
538
- text = text.to_s
539
- text.gsub(HTML_ESCAPE_REGEX, HTML_ESCAPE)
540
- end
541
- else
542
- def html_escape(text)
543
- text = text.to_s
544
- text.gsub(HTML_ESCAPE_REGEX) {|s| HTML_ESCAPE[s]}
545
- end
603
+ # Returns a copy of `text` with ampersands, angle brackets and quotes
604
+ # escaped into HTML entities.
605
+ #
606
+ # Note that if ActionView is loaded and XSS protection is enabled
607
+ # (as is the default for Rails 3.0+, and optional for version 2.3.5+),
608
+ # this won't escape text declared as "safe".
609
+ #
610
+ # @param text [String] The string to sanitize
611
+ # @return [String] The sanitized string
612
+ def html_escape(text)
613
+ ERB::Util.html_escape(text)
546
614
  end
547
615
 
548
- HTML_ESCAPE_ONCE_REGEX = /[\"><]|&(?!(?:[a-zA-Z]+|(#\d+));)/
616
+ HTML_ESCAPE_ONCE_REGEX = /['"><]|&(?!(?:[a-zA-Z]+|#(?:\d+|[xX][0-9a-fA-F]+));)/
549
617
 
550
- if RUBY_VERSION >= '1.9'
551
- # Include docs here so they are picked up by Yard
552
-
553
- # Escapes HTML entities in `text`, but without escaping an ampersand
554
- # that is already part of an escaped entity.
555
- #
556
- # @param text [String] The string to sanitize
557
- # @return [String] The sanitized string
558
- def escape_once(text)
559
- text = text.to_s
560
- text.gsub(HTML_ESCAPE_ONCE_REGEX, HTML_ESCAPE)
561
- end
562
- else
563
- def escape_once(text)
564
- text = text.to_s
565
- text.gsub(HTML_ESCAPE_ONCE_REGEX){|s| HTML_ESCAPE[s]}
566
- end
618
+ # Escapes HTML entities in `text`, but without escaping an ampersand
619
+ # that is already part of an escaped entity.
620
+ #
621
+ # @param text [String] The string to sanitize
622
+ # @return [String] The sanitized string
623
+ def escape_once(text)
624
+ text = text.to_s
625
+ text.gsub(HTML_ESCAPE_ONCE_REGEX, HTML_ESCAPE)
567
626
  end
568
627
 
569
628
  # Returns whether or not the current template is a Haml template.
@@ -593,7 +652,7 @@ MESSAGE
593
652
  # skip merging if no ids or classes found in name
594
653
  return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/
595
654
 
596
- return $1 || "div", Buffer.merge_attrs(
655
+ return $1 || "div", AttributeBuilder.merge_attributes!(
597
656
  Haml::Parser.parse_class_and_id($2), attributes_hash)
598
657
  end
599
658
 
@@ -630,22 +689,6 @@ MESSAGE
630
689
  _erbout = _erbout = _hamlout.buffer
631
690
  proc { |*args| proc.call(*args) }
632
691
  end
633
-
634
- def prettify(text)
635
- text = text.split(/^/)
636
- text.delete('')
637
-
638
- min_tabs = nil
639
- text.each do |line|
640
- tabs = line.index(/[^ ]/) || line.length
641
- min_tabs ||= tabs
642
- min_tabs = min_tabs > tabs ? tabs : min_tabs
643
- end
644
-
645
- text.map do |line|
646
- line.slice(min_tabs, line.length)
647
- end.join
648
- end
649
692
  end
650
693
  end
651
694
 
data/lib/haml/options.rb CHANGED
@@ -1,40 +1,19 @@
1
+ # frozen_string_literal: true
1
2
  module Haml
2
3
  # This class encapsulates all of the configuration options that Haml
3
4
  # understands. Please see the {file:REFERENCE.md#options Haml Reference} to
4
5
  # learn how to set the options.
5
6
  class Options
6
7
 
7
- @defaults = {
8
- :attr_wrapper => "'",
9
- :autoclose => %w(area base basefont br col command embed frame
10
- hr img input isindex keygen link menuitem meta
11
- param source track wbr),
12
- :encoding => "UTF-8",
13
- :escape_attrs => true,
14
- :escape_html => false,
15
- :filename => '(haml)',
16
- :format => :html5,
17
- :hyphenate_data_attrs => true,
18
- :line => 1,
19
- :mime_type => 'text/html',
20
- :preserve => %w(textarea pre code),
21
- :remove_whitespace => false,
22
- :suppress_eval => false,
23
- :ugly => false,
24
- :cdata => false,
25
- :parser_class => ::Haml::Parser,
26
- :compiler_class => ::Haml::Compiler
27
- }
28
-
29
8
  @valid_formats = [:html4, :html5, :xhtml]
30
9
 
31
- @buffer_option_keys = [:autoclose, :preserve, :attr_wrapper, :ugly, :format,
10
+ @buffer_option_keys = [:autoclose, :preserve, :attr_wrapper, :format,
32
11
  :encoding, :escape_html, :escape_attrs, :hyphenate_data_attrs, :cdata]
33
12
 
34
13
  # The default option values.
35
14
  # @return Hash
36
15
  def self.defaults
37
- @defaults
16
+ @defaults ||= Haml::TempleEngine.options.to_hash.merge(encoding: 'UTF-8')
38
17
  end
39
18
 
40
19
  # An array of valid values for the `:format` option.
@@ -50,6 +29,22 @@ module Haml
50
29
  @buffer_option_keys
51
30
  end
52
31
 
32
+ # Returns a subset of defaults: those that {Haml::Buffer} cares about.
33
+ # @return [{Symbol => Object}] The options hash
34
+ def self.buffer_defaults
35
+ @buffer_defaults ||= buffer_option_keys.inject({}) do |hash, key|
36
+ hash.merge(key => defaults[key])
37
+ end
38
+ end
39
+
40
+ def self.wrap(options)
41
+ if options.is_a?(Options)
42
+ options
43
+ else
44
+ Options.new(options)
45
+ end
46
+ end
47
+
53
48
  # The character that should wrap element attributes. This defaults to `'`
54
49
  # (an apostrophe). Characters of this type within the attributes will be
55
50
  # escaped (e.g. by replacing them with `&apos;`) if the character is an
@@ -63,7 +58,6 @@ module Haml
63
58
  attr_accessor :autoclose
64
59
 
65
60
  # The encoding to use for the HTML output.
66
- # Only available on Ruby 1.9 or higher.
67
61
  # This can be a string or an `Encoding` Object. Note that Haml **does not**
68
62
  # automatically re-encode Ruby values; any strings coming from outside the
69
63
  # application should be converted before being passed into the Haml
@@ -146,13 +140,6 @@ module Haml
146
140
  # Defaults to `false`.
147
141
  attr_accessor :suppress_eval
148
142
 
149
- # If set to `true`, Haml makes no attempt to properly indent or format the
150
- # HTML output. This significantly improves rendering performance but makes
151
- # viewing the source unpleasant.
152
- #
153
- # Defaults to `true` in Rails production mode, and `false` everywhere else.
154
- attr_accessor :ugly
155
-
156
143
  # Whether to include CDATA sections around javascript and css blocks when
157
144
  # using the `:javascript` or `:css` filters.
158
145
  #
@@ -169,9 +156,20 @@ module Haml
169
156
  # The compiler class to use. Defaults to Haml::Compiler.
170
157
  attr_accessor :compiler_class
171
158
 
159
+ # Enable template tracing. If true, it will add a 'data-trace' attribute to
160
+ # each tag generated by Haml. The value of the attribute will be the
161
+ # source template name and the line number from which the tag was generated,
162
+ # separated by a colon. On Rails applications, the path given will be a
163
+ # relative path as from the views directory. On non-Rails applications,
164
+ # the path will be the full path.
165
+ attr_accessor :trace
166
+
167
+ # Key is filter name in String and value is Class to use. Defaults to {}.
168
+ attr_accessor :filters
169
+
172
170
  def initialize(values = {}, &block)
173
171
  defaults.each {|k, v| instance_variable_set :"@#{k}", v}
174
- values.reject {|k, v| !defaults.has_key?(k) || v.nil?}.each {|k, v| send("#{k}=", v)}
172
+ values.each {|k, v| send("#{k}=", v) if defaults.has_key?(k) && !v.nil?}
175
173
  yield if block_given?
176
174
  end
177
175
 
@@ -188,8 +186,7 @@ module Haml
188
186
  send "#{key}=", value
189
187
  end
190
188
 
191
- [:escape_attrs, :hyphenate_data_attrs, :remove_whitespace, :suppress_eval,
192
- :ugly].each do |method|
189
+ [:escape_attrs, :hyphenate_data_attrs, :remove_whitespace, :suppress_eval].each do |method|
193
190
  class_eval(<<-END)
194
191
  def #{method}?
195
192
  !! @#{method}
@@ -241,21 +238,16 @@ module Haml
241
238
  end
242
239
 
243
240
  def remove_whitespace=(value)
244
- @ugly = true if value
245
241
  @remove_whitespace = value
246
242
  end
247
243
 
248
- if RUBY_VERSION < "1.9"
249
- attr_writer :encoding
250
- else
251
- def encoding=(value)
252
- return unless value
253
- @encoding = value.is_a?(Encoding) ? value.name : value.to_s
254
- @encoding = "UTF-8" if @encoding.upcase == "US-ASCII"
255
- end
244
+ def encoding=(value)
245
+ return unless value
246
+ @encoding = value.is_a?(Encoding) ? value.name : value.to_s
247
+ @encoding = "UTF-8" if @encoding.upcase == "US-ASCII"
256
248
  end
257
249
 
258
- # Returns a subset of options: those that {Haml::Buffer} cares about.
250
+ # Returns a non-default subset of options: those that {Haml::Buffer} cares about.
259
251
  # All of the values here are such that when `#inspect` is called on the hash,
260
252
  # it can be `Kernel#eval`ed to get the same result back.
261
253
  #
@@ -264,7 +256,10 @@ module Haml
264
256
  # @return [{Symbol => Object}] The options hash
265
257
  def for_buffer
266
258
  self.class.buffer_option_keys.inject({}) do |hash, key|
267
- hash[key] = send(key)
259
+ value = public_send(key)
260
+ if self.class.buffer_defaults[key] != value
261
+ hash[key] = value
262
+ end
268
263
  hash
269
264
  end
270
265
  end
@@ -274,6 +269,5 @@ module Haml
274
269
  def defaults
275
270
  self.class.defaults
276
271
  end
277
-
278
272
  end
279
273
  end