haml 4.0.7 → 5.0.4

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 (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
data/lib/haml/compiler.rb CHANGED
@@ -1,4 +1,7 @@
1
- require 'cgi'
1
+ # frozen_string_literal: false
2
+ require 'haml/attribute_builder'
3
+ require 'haml/attribute_compiler'
4
+ require 'haml/temple_line_counter'
2
5
 
3
6
  module Haml
4
7
  class Compiler
@@ -7,15 +10,21 @@ module Haml
7
10
  attr_accessor :options
8
11
 
9
12
  def initialize(options)
10
- @options = options
11
- @output_tabs = 0
13
+ @options = Options.wrap(options)
12
14
  @to_merge = []
13
- @precompiled = ''
15
+ @temple = [:multi]
16
+ @node = nil
17
+ @filters = Filters.defined.merge(options[:filters])
18
+ @attribute_compiler = AttributeCompiler.new(@options)
19
+ end
20
+
21
+ def call(node)
22
+ compile(node)
23
+ @temple
14
24
  end
15
25
 
16
26
  def compile(node)
17
- parent = instance_variable_defined?('@node') ? @node : nil
18
- @node = node
27
+ parent, @node = @node, node
19
28
  if node.children.empty?
20
29
  send(:"compile_#{node.type}")
21
30
  else
@@ -25,79 +34,16 @@ module Haml
25
34
  @node = parent
26
35
  end
27
36
 
28
- if RUBY_VERSION < "1.9"
29
- # The source code that is evaluated to produce the Haml document.
30
- #
31
- # In Ruby 1.9, this is automatically converted to the correct encoding
32
- # (see {file:REFERENCE.md#encodings the `:encoding` option}).
33
- #
34
- # @return [String]
35
- def precompiled
36
- @precompiled
37
- end
38
- else
39
- def precompiled
40
- encoding = Encoding.find(@options[:encoding])
41
- return @precompiled.force_encoding(encoding) if encoding == Encoding::BINARY
42
- return @precompiled.encode(encoding)
43
- end
44
- end
45
-
46
- def precompiled_with_return_value
47
- precompiled + ";" + precompiled_method_return_value
48
- end
49
-
50
- # Returns the precompiled string with the preamble and postamble.
51
- #
52
- # Initializes to ActionView::OutputBuffer when available; this is necessary
53
- # to avoid ordering issues with partial layouts in Rails. If not available,
54
- # initializes to nil.
55
- def precompiled_with_ambles(local_names)
56
- preamble = <<END.gsub("\n", ";")
57
- begin
58
- extend Haml::Helpers
59
- _hamlout = @haml_buffer = Haml::Buffer.new(haml_buffer, #{options.for_buffer.inspect})
60
- _erbout = _hamlout.buffer
61
- @output_buffer = output_buffer ||= ActionView::OutputBuffer.new rescue nil
62
- END
63
- postamble = <<END.gsub("\n", ";")
64
- #{precompiled_method_return_value}
65
- ensure
66
- @haml_buffer = @haml_buffer.upper if @haml_buffer
67
- end
68
- END
69
- preamble + locals_code(local_names) + precompiled + postamble
70
- end
71
-
72
37
  private
73
38
 
74
- # Returns the string used as the return value of the precompiled method.
75
- # This method exists so it can be monkeypatched to return modified values.
76
- def precompiled_method_return_value
77
- "_erbout"
78
- end
79
-
80
- def locals_code(names)
81
- names = names.keys if Hash == names
82
-
83
- names.map do |name|
84
- # Can't use || because someone might explicitly pass in false with a symbol
85
- sym_local = "_haml_locals[#{inspect_obj(name.to_sym)}]"
86
- str_local = "_haml_locals[#{inspect_obj(name.to_s)}]"
87
- "#{name} = #{sym_local}.nil? ? #{str_local} : #{sym_local}"
88
- end.join(';') + ';'
89
- end
90
-
91
39
  def compile_root
92
- @dont_indent_next_line = @dont_tab_up_next_text = false
93
40
  @output_line = 1
94
- @indentation = nil
95
- yield
41
+ yield if block_given?
96
42
  flush_merged_text
97
43
  end
98
44
 
99
45
  def compile_plain
100
- push_text @node.value[:text]
46
+ push_text("#{@node.value[:text]}\n")
101
47
  end
102
48
 
103
49
  def nuke_inner_whitespace?(node)
@@ -119,15 +65,11 @@ END
119
65
  end
120
66
 
121
67
  def compile_silent_script
122
- return if @options[:suppress_eval]
68
+ return if @options.suppress_eval
123
69
  push_silent(@node.value[:text])
124
70
  keyword = @node.value[:keyword]
125
71
 
126
72
  if block_given?
127
- # Store these values because for conditional statements,
128
- # we want to restore them for each branch
129
- @node.value[:dont_indent_next_line] = @dont_indent_next_line
130
- @node.value[:dont_tab_up_next_text] = @dont_tab_up_next_text
131
73
  yield
132
74
  push_silent("end", :can_suppress) unless @node.value[:dont_push_end]
133
75
  elsif keyword == "end"
@@ -137,10 +79,6 @@ END
137
79
  @node.parent.value[:dont_push_end] = true
138
80
  end
139
81
  # Don't restore dont_* for end because it isn't a conditional branch.
140
- elsif Parser::MID_BLOCK_KEYWORDS.include?(keyword)
141
- # Restore dont_* for this conditional branch
142
- @dont_indent_next_line = @node.parent.value[:dont_indent_next_line]
143
- @dont_tab_up_next_text = @node.parent.value[:dont_tab_up_next_text]
144
82
  end
145
83
  end
146
84
 
@@ -152,117 +90,84 @@ END
152
90
  # Get rid of whitespace outside of the tag if we need to
153
91
  rstrip_buffer! if t[:nuke_outer_whitespace]
154
92
 
155
- dont_indent_next_line =
156
- (t[:nuke_outer_whitespace] && !block_given?) ||
157
- (t[:nuke_inner_whitespace] && block_given?)
158
-
159
- if @options[:suppress_eval]
160
- object_ref = "nil"
93
+ if @options.suppress_eval
94
+ object_ref = :nil
161
95
  parse = false
162
96
  value = t[:parse] ? nil : t[:value]
163
- attributes_hashes = {}
164
- preserve_script = false
97
+ dynamic_attributes = Haml::Parser::DynamicAttributes.new
165
98
  else
166
99
  object_ref = t[:object_ref]
167
100
  parse = t[:parse]
168
101
  value = t[:value]
169
- attributes_hashes = t[:attributes_hashes]
170
- preserve_script = t[:preserve_script]
102
+ dynamic_attributes = t[:dynamic_attributes]
171
103
  end
172
104
 
173
- # Check if we can render the tag directly to text and not process it in the buffer
174
- if object_ref == "nil" && attributes_hashes.empty? && !preserve_script
175
- tag_closed = !block_given? && !t[:self_closing] && !parse
176
-
177
- open_tag = prerender_tag(t[:name], t[:self_closing], t[:attributes])
178
- if tag_closed
179
- open_tag << "#{value}</#{t[:name]}>"
180
- open_tag << "\n" unless t[:nuke_outer_whitespace]
181
- elsif !(parse || t[:nuke_inner_whitespace] ||
182
- (t[:self_closing] && t[:nuke_outer_whitespace]))
183
- open_tag << "\n"
184
- end
185
-
186
- push_merged_text(open_tag,
187
- tag_closed || t[:self_closing] || t[:nuke_inner_whitespace] ? 0 : 1,
188
- !t[:nuke_outer_whitespace])
105
+ if @options[:trace]
106
+ t[:attributes].merge!({"data-trace" => @options.filename.split('/views').last << ":" << @node.line.to_s})
107
+ end
189
108
 
190
- @dont_indent_next_line = dont_indent_next_line
191
- return if tag_closed
192
- else
193
- if attributes_hashes.empty?
194
- attributes_hashes = ''
195
- elsif attributes_hashes.size == 1
196
- attributes_hashes = ", #{attributes_hashes.first}"
109
+ push_text("<#{t[:name]}")
110
+ push_temple(@attribute_compiler.compile(t[:attributes], object_ref, dynamic_attributes))
111
+ push_text(
112
+ if t[:self_closing] && @options.xhtml?
113
+ " />#{"\n" unless t[:nuke_outer_whitespace]}"
197
114
  else
198
- attributes_hashes = ", (#{attributes_hashes.join(").merge(")})"
199
- end
200
-
201
- push_merged_text "<#{t[:name]}", 0, !t[:nuke_outer_whitespace]
202
- push_generated_script(
203
- "_hamlout.attributes(#{inspect_obj(t[:attributes])}, #{object_ref}#{attributes_hashes})")
204
- concat_merged_text(
205
- if t[:self_closing] && @options.xhtml?
206
- " />" + (t[:nuke_outer_whitespace] ? "" : "\n")
207
- else
208
- ">" + ((if t[:self_closing] && @options.html?
209
- t[:nuke_outer_whitespace]
210
- else
211
- !block_given? || t[:preserve_tag] || t[:nuke_inner_whitespace]
212
- end) ? "" : "\n")
213
- end)
214
-
215
- if value && !parse
216
- concat_merged_text("#{value}</#{t[:name]}>#{t[:nuke_outer_whitespace] ? "" : "\n"}")
217
- elsif !t[:nuke_inner_whitespace] && !t[:self_closing]
218
- @to_merge << [:text, '', 1]
115
+ ">#{"\n" unless (t[:self_closing] && @options.html?) ? t[:nuke_outer_whitespace] : (!block_given? || t[:preserve_tag] || t[:nuke_inner_whitespace])}"
219
116
  end
117
+ )
220
118
 
221
- @dont_indent_next_line = dont_indent_next_line
119
+ if value && !parse
120
+ push_text("#{value}</#{t[:name]}>#{"\n" unless t[:nuke_outer_whitespace]}")
222
121
  end
223
122
 
224
123
  return if t[:self_closing]
225
124
 
226
125
  if value.nil?
227
- @output_tabs += 1 unless t[:nuke_inner_whitespace]
228
126
  yield if block_given?
229
- @output_tabs -= 1 unless t[:nuke_inner_whitespace]
230
127
  rstrip_buffer! if t[:nuke_inner_whitespace]
231
- push_merged_text("</#{t[:name]}>" + (t[:nuke_outer_whitespace] ? "" : "\n"),
232
- t[:nuke_inner_whitespace] ? 0 : -1, !t[:nuke_inner_whitespace])
233
- @dont_indent_next_line = t[:nuke_outer_whitespace]
128
+ push_text("</#{t[:name]}>#{"\n" unless t[:nuke_outer_whitespace]}")
234
129
  return
235
130
  end
236
131
 
237
132
  if parse
238
133
  push_script(value, t.merge(:in_tag => true))
239
- concat_merged_text("</#{t[:name]}>" + (t[:nuke_outer_whitespace] ? "" : "\n"))
134
+ push_text("</#{t[:name]}>#{"\n" unless t[:nuke_outer_whitespace]}")
240
135
  end
241
136
  end
242
137
 
243
138
  def compile_comment
244
- open = "<!--#{@node.value[:conditional]}"
139
+ condition = "#{@node.value[:conditional]}>" if @node.value[:conditional]
140
+ revealed = @node.value[:revealed]
141
+
142
+ open = "<!--#{condition}#{'<!-->' if revealed}"
143
+
144
+ close = "#{'<!--' if revealed}#{'<![endif]' if condition}-->"
245
145
 
246
- # Render it statically if possible
247
146
  unless block_given?
248
- push_text("#{open} #{@node.value[:text]} #{@node.value[:conditional] ? "<![endif]-->" : "-->"}")
147
+ push_text("#{open} ")
148
+
149
+ if @node.value[:parse]
150
+ push_script(@node.value[:text], :in_tag => true, :nuke_inner_whitespace => true)
151
+ else
152
+ push_text(@node.value[:text])
153
+ end
154
+
155
+ push_text(" #{close}\n")
249
156
  return
250
157
  end
251
158
 
252
- push_text(open, 1)
253
- @output_tabs += 1
159
+ push_text("#{open}\n")
254
160
  yield if block_given?
255
- @output_tabs -= 1
256
- push_text(@node.value[:conditional] ? "<![endif]-->" : "-->", -1)
161
+ push_text("#{close}\n")
257
162
  end
258
163
 
259
164
  def compile_doctype
260
165
  doctype = text_for_doctype
261
- push_text doctype if doctype
166
+ push_text("#{doctype}\n") if doctype
262
167
  end
263
168
 
264
169
  def compile_filter
265
- unless filter = Filters.defined[@node.value[:name]]
170
+ unless filter = @filters[@node.value[:name]]
266
171
  name = @node.value[:name]
267
172
  if ["maruku", "textile"].include?(name)
268
173
  raise Error.new(Error.message(:install_haml_contrib, name), @node.line - 1)
@@ -276,7 +181,7 @@ END
276
181
  def text_for_doctype
277
182
  if @node.value[:type] == "xml"
278
183
  return nil if @options.html?
279
- wrapper = @options[:attr_wrapper]
184
+ wrapper = @options.attr_wrapper
280
185
  return "<?xml version=#{wrapper}1.0#{wrapper} encoding=#{wrapper}#{@node.value[:encoding] || "utf-8"}#{wrapper} ?>"
281
186
  end
282
187
 
@@ -315,83 +220,52 @@ END
315
220
  flush_merged_text
316
221
  return if can_suppress && @options.suppress_eval?
317
222
  newline = (text == "end") ? ";" : "\n"
318
- @precompiled << "#{resolve_newlines}#{text}#{newline}"
319
- @output_line += (text + newline).count("\n")
320
- end
321
-
322
- # Adds `text` to `@buffer` with appropriate tabulation
323
- # without parsing it.
324
- def push_merged_text(text, tab_change = 0, indent = true)
325
- text = !indent || @dont_indent_next_line || @options[:ugly] ? text : "#{' ' * @output_tabs}#{text}"
326
- @to_merge << [:text, text, tab_change]
327
- @dont_indent_next_line = false
223
+ @temple << [:code, "#{resolve_newlines}#{text}#{newline}"]
224
+ @output_line = @output_line + text.count("\n") + newline.count("\n")
328
225
  end
329
226
 
330
- # Concatenate `text` to `@buffer` without tabulation.
331
- def concat_merged_text(text)
332
- @to_merge << [:text, text, 0]
227
+ # Adds `text` to `@buffer`.
228
+ def push_text(text)
229
+ @to_merge << [:text, text]
333
230
  end
334
231
 
335
- def push_text(text, tab_change = 0)
336
- push_merged_text("#{text}\n", tab_change)
232
+ def push_temple(temple)
233
+ flush_merged_text
234
+ @temple.concat([[:newline]] * resolve_newlines.count("\n"))
235
+ @temple << temple
236
+ @output_line += TempleLineCounter.count_lines(temple)
337
237
  end
338
238
 
339
239
  def flush_merged_text
340
240
  return if @to_merge.empty?
341
241
 
342
- str = ""
343
- mtabs = 0
344
- @to_merge.each do |type, val, tabs|
242
+ @to_merge.each do |type, val|
345
243
  case type
346
244
  when :text
347
- str << inspect_obj(val)[1...-1]
348
- mtabs += tabs
245
+ @temple << [:static, val]
349
246
  when :script
350
- if mtabs != 0 && !@options[:ugly]
351
- val = "_hamlout.adjust_tabs(#{mtabs}); " + val
352
- end
353
- str << "\#{#{val}}"
354
- mtabs = 0
247
+ @temple << [:dynamic, val]
355
248
  else
356
249
  raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Compiler@to_merge.")
357
250
  end
358
251
  end
359
252
 
360
- unless str.empty?
361
- @precompiled <<
362
- if @options[:ugly]
363
- "_hamlout.buffer << \"#{str}\";"
364
- else
365
- "_hamlout.push_text(\"#{str}\", #{mtabs}, #{@dont_tab_up_next_text.inspect});"
366
- end
367
- end
368
253
  @to_merge = []
369
- @dont_tab_up_next_text = false
370
254
  end
371
255
 
372
256
  # Causes `text` to be evaluated in the context of
373
257
  # the scope object and the result to be added to `@buffer`.
374
258
  #
375
- # If `opts[:preserve_script]` is true, Haml::Helpers#find_and_flatten is run on
259
+ # If `opts[:preserve_script]` is true, Haml::Helpers#find_and_preserve is run on
376
260
  # the result before it is added to `@buffer`
377
261
  def push_script(text, opts = {})
378
262
  return if @options.suppress_eval?
379
263
 
380
- args = %w[preserve_script in_tag preserve_tag escape_html nuke_inner_whitespace]
381
- args.map! {|name| opts[name.to_sym]}
382
- args << !block_given? << @options[:ugly]
383
-
384
- no_format = @options[:ugly] &&
385
- !(opts[:preserve_script] || opts[:preserve_tag] || opts[:escape_html])
386
- output_expr = "(#{text}\n)"
387
- static_method = "_hamlout.#{static_method_name(:format_script, *args)}"
388
-
389
- # Prerender tabulation unless we're in a tag
390
- push_merged_text '' unless opts[:in_tag]
264
+ no_format = !(opts[:preserve_script] || opts[:preserve_tag] || opts[:escape_html])
391
265
 
392
266
  unless block_given?
393
- push_generated_script(no_format ? "#{text}\n" : "#{static_method}(#{output_expr});")
394
- concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace]
267
+ push_generated_script(no_format ? "(#{text}\n).to_s" : build_script_formatter("(#{text}\n)", opts))
268
+ push_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace]
395
269
  return
396
270
  end
397
271
 
@@ -399,117 +273,35 @@ END
399
273
  push_silent "haml_temp = #{text}"
400
274
  yield
401
275
  push_silent('end', :can_suppress) unless @node.value[:dont_push_end]
402
- @precompiled << "_hamlout.buffer << #{no_format ? "haml_temp.to_s;" : "#{static_method}(haml_temp);"}"
403
- concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace] || @options[:ugly]
404
- end
405
-
406
- def push_generated_script(text)
407
- @to_merge << [:script, resolve_newlines + text]
408
- @output_line += text.count("\n")
276
+ @temple << [:dynamic, no_format ? 'haml_temp.to_s;' : build_script_formatter('haml_temp', opts)]
409
277
  end
410
278
 
411
- # This is a class method so it can be accessed from Buffer.
412
- def self.build_attributes(is_html, attr_wrapper, escape_attrs, hyphenate_data_attrs, attributes = {})
413
- # @TODO this is an absolutely ridiculous amount of arguments. At least
414
- # some of this needs to be moved into an instance method.
415
- quote_escape = attr_wrapper == '"' ? "&#x0022;" : "&#x0027;"
416
- other_quote_char = attr_wrapper == '"' ? "'" : '"'
417
- join_char = hyphenate_data_attrs ? '-' : '_'
418
-
419
- attributes.each do |key, value|
420
- if value.is_a?(Hash)
421
- data_attributes = attributes.delete(key)
422
- data_attributes = flatten_data_attributes(data_attributes, '', join_char)
423
- data_attributes = build_data_keys(data_attributes, hyphenate_data_attrs, key)
424
- attributes = data_attributes.merge(attributes)
425
- end
279
+ def build_script_formatter(text, opts)
280
+ text = "(#{text}).to_s"
281
+ if opts[:escape_html]
282
+ text = "::Haml::Helpers.html_escape(#{text})"
426
283
  end
427
-
428
- result = attributes.collect do |attr, value|
429
- next if value.nil?
430
-
431
- value = filter_and_join(value, ' ') if attr == 'class'
432
- value = filter_and_join(value, '_') if attr == 'id'
433
-
434
- if value == true
435
- next " #{attr}" if is_html
436
- next " #{attr}=#{attr_wrapper}#{attr}#{attr_wrapper}"
437
- elsif value == false
438
- next
439
- end
440
-
441
- escaped =
442
- if escape_attrs == :once
443
- Haml::Helpers.escape_once(value.to_s)
444
- elsif escape_attrs
445
- Haml::Helpers.html_escape(value.to_s)
446
- else
447
- value.to_s
448
- end
449
- value = Haml::Helpers.preserve(escaped)
450
- if escape_attrs
451
- # We want to decide whether or not to escape quotes
452
- value.gsub!(/&quot;|&#x0022;/, '"')
453
- this_attr_wrapper = attr_wrapper
454
- if value.include? attr_wrapper
455
- if value.include? other_quote_char
456
- value.gsub!(attr_wrapper, quote_escape)
457
- else
458
- this_attr_wrapper = other_quote_char
459
- end
460
- end
461
- else
462
- this_attr_wrapper = attr_wrapper
463
- end
464
- " #{attr}=#{this_attr_wrapper}#{value}#{this_attr_wrapper}"
284
+ if opts[:nuke_inner_whitespace]
285
+ text = "(#{text}).strip"
465
286
  end
466
- result.compact.sort.join
467
- end
468
-
469
- def self.filter_and_join(value, separator)
470
- return "" if value == ""
471
- value = [value] unless value.is_a?(Array)
472
- value = value.flatten.collect {|item| item ? item.to_s : nil}.compact.join(separator)
473
- return !value.empty? && value
474
- end
475
-
476
- def self.build_data_keys(data_hash, hyphenate, attr_name="data")
477
- Hash[data_hash.map do |name, value|
478
- if name == nil
479
- [attr_name, value]
480
- elsif hyphenate
481
- ["#{attr_name}-#{name.to_s.gsub(/_/, '-')}", value]
482
- else
483
- ["#{attr_name}-#{name}", value]
484
- end
485
- end]
486
- end
487
-
488
- def self.flatten_data_attributes(data, key, join_char, seen = [])
489
- return {key => data} unless data.is_a?(Hash)
490
-
491
- return {key => nil} if seen.include? data.object_id
492
- seen << data.object_id
493
-
494
- data.sort {|x, y| x[0].to_s <=> y[0].to_s}.inject({}) do |hash, array|
495
- k, v = array
496
- joined = key == '' ? k : [key, k].join(join_char)
497
- hash.merge! flatten_data_attributes(v, joined, join_char, seen)
287
+ if opts[:preserve_tag]
288
+ text = "_hamlout.fix_textareas!(::Haml::Helpers.preserve(#{text}))"
289
+ elsif opts[:preserve_script]
290
+ text = "_hamlout.fix_textareas!(::Haml::Helpers.find_and_preserve(#{text}, _hamlout.options[:preserve]))"
498
291
  end
292
+ "#{text};"
499
293
  end
500
294
 
501
- def prerender_tag(name, self_close, attributes)
502
- # TODO: consider just passing in the damn options here
503
- attributes_string = Compiler.build_attributes(
504
- @options.html?, @options[:attr_wrapper], @options[:escape_attrs], @options[:hyphenate_data_attrs], attributes)
505
- "<#{name}#{attributes_string}#{self_close && @options.xhtml? ? ' /' : ''}>"
295
+ def push_generated_script(text)
296
+ @to_merge << [:script, resolve_newlines + text]
297
+ @output_line += text.count("\n")
506
298
  end
507
299
 
508
300
  def resolve_newlines
509
301
  diff = @node.line - @output_line
510
302
  return "" if diff <= 0
511
303
  @output_line = @node.line
512
- "\n" * [diff, 0].max
304
+ "\n" * diff
513
305
  end
514
306
 
515
307
  # Get rid of and whitespace at the end of the buffer
@@ -518,7 +310,6 @@ END
518
310
  last = @to_merge[index]
519
311
  if last.nil?
520
312
  push_silent("_hamlout.rstrip!", false)
521
- @dont_tab_up_next_text = true
522
313
  return
523
314
  end
524
315