haml 4.0.7 → 5.0.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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +42 -4
  4. data/FAQ.md +4 -14
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +85 -42
  7. data/REFERENCE.md +108 -57
  8. data/Rakefile +46 -54
  9. data/lib/haml/attribute_builder.rb +163 -0
  10. data/lib/haml/attribute_compiler.rb +215 -0
  11. data/lib/haml/attribute_parser.rb +144 -0
  12. data/lib/haml/buffer.rb +22 -132
  13. data/lib/haml/compiler.rb +87 -295
  14. data/lib/haml/engine.rb +25 -41
  15. data/lib/haml/error.rb +3 -0
  16. data/lib/haml/escapable.rb +49 -0
  17. data/lib/haml/exec.rb +33 -19
  18. data/lib/haml/filters.rb +18 -24
  19. data/lib/haml/generator.rb +41 -0
  20. data/lib/haml/helpers/action_view_extensions.rb +3 -2
  21. data/lib/haml/helpers/action_view_mods.rb +36 -58
  22. data/lib/haml/helpers/action_view_xss_mods.rb +1 -0
  23. data/lib/haml/helpers/safe_erubi_template.rb +27 -0
  24. data/lib/haml/helpers/safe_erubis_template.rb +4 -1
  25. data/lib/haml/helpers/xss_mods.rb +18 -12
  26. data/lib/haml/helpers.rb +133 -90
  27. data/lib/haml/options.rb +38 -47
  28. data/lib/haml/parser.rb +278 -216
  29. data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
  30. data/lib/haml/railtie.rb +21 -12
  31. data/lib/haml/sass_rails_filter.rb +17 -4
  32. data/lib/haml/template/options.rb +12 -2
  33. data/lib/haml/template.rb +12 -6
  34. data/lib/haml/temple_engine.rb +120 -0
  35. data/lib/haml/temple_line_counter.rb +29 -0
  36. data/lib/haml/util.rb +80 -199
  37. data/lib/haml/version.rb +2 -1
  38. data/lib/haml.rb +1 -0
  39. data/test/attribute_parser_test.rb +101 -0
  40. data/test/engine_test.rb +287 -176
  41. data/test/filters_test.rb +32 -19
  42. data/test/gemfiles/Gemfile.rails-4.0.x +9 -3
  43. data/test/gemfiles/Gemfile.rails-4.0.x.lock +87 -0
  44. data/test/gemfiles/Gemfile.rails-4.1.x +5 -0
  45. data/test/gemfiles/Gemfile.rails-4.2.x +5 -0
  46. data/test/gemfiles/Gemfile.rails-5.0.x +4 -0
  47. data/test/helper_test.rb +224 -112
  48. data/test/options_test.rb +22 -0
  49. data/test/parser_test.rb +71 -4
  50. data/test/results/bemit.xhtml +4 -0
  51. data/test/results/eval_suppressed.xhtml +4 -4
  52. data/test/results/helpers.xhtml +43 -41
  53. data/test/results/helpful.xhtml +6 -3
  54. data/test/results/just_stuff.xhtml +21 -20
  55. data/test/results/list.xhtml +9 -9
  56. data/test/results/nuke_inner_whitespace.xhtml +22 -22
  57. data/test/results/nuke_outer_whitespace.xhtml +84 -92
  58. data/test/results/original_engine.xhtml +17 -17
  59. data/test/results/partial_layout.xhtml +4 -3
  60. data/test/results/partial_layout_erb.xhtml +4 -3
  61. data/test/results/partials.xhtml +11 -10
  62. data/test/results/silent_script.xhtml +63 -63
  63. data/test/results/standard.xhtml +156 -159
  64. data/test/results/tag_parsing.xhtml +19 -19
  65. data/test/results/very_basic.xhtml +2 -2
  66. data/test/results/whitespace_handling.xhtml +77 -76
  67. data/test/template_test.rb +24 -56
  68. data/test/template_test_helper.rb +38 -0
  69. data/test/templates/bemit.haml +3 -0
  70. data/test/templates/just_stuff.haml +1 -0
  71. data/test/templates/standard_ugly.haml +1 -0
  72. data/test/templates/with_bom.haml +1 -0
  73. data/test/temple_line_counter_test.rb +40 -0
  74. data/test/test_helper.rb +26 -8
  75. data/test/util_test.rb +6 -47
  76. metadata +53 -43
  77. data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
  78. data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
  79. data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
  80. data/test/haml-spec/LICENSE +0 -14
  81. data/test/haml-spec/README.md +0 -106
  82. data/test/haml-spec/lua_haml_spec.lua +0 -38
  83. data/test/haml-spec/perl_haml_test.pl +0 -81
  84. data/test/haml-spec/ruby_haml_test.rb +0 -23
  85. data/test/haml-spec/tests.json +0 -660
  86. data/test/templates/_av_partial_1_ugly.haml +0 -9
  87. data/test/templates/_av_partial_2_ugly.haml +0 -5
  88. data/test/templates/action_view_ugly.haml +0 -47
  89. data/test/templates/standard_ugly.haml +0 -43
@@ -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 ")
199
- result = "\n #{result.strip}\n"
208
+ result.gsub!("\n", "\n ")
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,17 @@ 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
+
172
167
  def initialize(values = {}, &block)
173
168
  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)}
169
+ values.each {|k, v| send("#{k}=", v) if defaults.has_key?(k) && !v.nil?}
175
170
  yield if block_given?
176
171
  end
177
172
 
@@ -188,8 +183,7 @@ module Haml
188
183
  send "#{key}=", value
189
184
  end
190
185
 
191
- [:escape_attrs, :hyphenate_data_attrs, :remove_whitespace, :suppress_eval,
192
- :ugly].each do |method|
186
+ [:escape_attrs, :hyphenate_data_attrs, :remove_whitespace, :suppress_eval].each do |method|
193
187
  class_eval(<<-END)
194
188
  def #{method}?
195
189
  !! @#{method}
@@ -241,21 +235,16 @@ module Haml
241
235
  end
242
236
 
243
237
  def remove_whitespace=(value)
244
- @ugly = true if value
245
238
  @remove_whitespace = value
246
239
  end
247
240
 
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
241
+ def encoding=(value)
242
+ return unless value
243
+ @encoding = value.is_a?(Encoding) ? value.name : value.to_s
244
+ @encoding = "UTF-8" if @encoding.upcase == "US-ASCII"
256
245
  end
257
246
 
258
- # Returns a subset of options: those that {Haml::Buffer} cares about.
247
+ # Returns a non-default subset of options: those that {Haml::Buffer} cares about.
259
248
  # All of the values here are such that when `#inspect` is called on the hash,
260
249
  # it can be `Kernel#eval`ed to get the same result back.
261
250
  #
@@ -264,7 +253,10 @@ module Haml
264
253
  # @return [{Symbol => Object}] The options hash
265
254
  def for_buffer
266
255
  self.class.buffer_option_keys.inject({}) do |hash, key|
267
- hash[key] = send(key)
256
+ value = public_send(key)
257
+ if self.class.buffer_defaults[key] != value
258
+ hash[key] = value
259
+ end
268
260
  hash
269
261
  end
270
262
  end
@@ -274,6 +266,5 @@ module Haml
274
266
  def defaults
275
267
  self.class.defaults
276
268
  end
277
-
278
269
  end
279
270
  end