haml 4.0.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +117 -5
  4. data/FAQ.md +7 -17
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +85 -42
  7. data/REFERENCE.md +181 -86
  8. data/Rakefile +47 -51
  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 +38 -128
  13. data/lib/haml/compiler.rb +88 -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 +20 -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 +44 -66
  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 +16 -4
  25. data/lib/haml/helpers/xss_mods.rb +18 -12
  26. data/lib/haml/helpers.rb +122 -58
  27. data/lib/haml/options.rb +39 -46
  28. data/lib/haml/parser.rb +278 -217
  29. data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
  30. data/lib/haml/railtie.rb +21 -11
  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 +2 -1
  39. data/test/attribute_parser_test.rb +101 -0
  40. data/test/engine_test.rb +306 -176
  41. data/test/filters_test.rb +32 -19
  42. data/test/gemfiles/Gemfile.rails-4.0.x +11 -0
  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 +282 -96
  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 +56 -50
  67. data/test/template_test.rb +44 -53
  68. data/test/template_test_helper.rb +38 -0
  69. data/test/templates/_text_area_helper.html.haml +4 -0
  70. data/test/templates/bemit.haml +3 -0
  71. data/test/templates/just_stuff.haml +1 -0
  72. data/test/templates/partial_layout_erb.erb +1 -1
  73. data/test/templates/standard_ugly.haml +1 -0
  74. data/test/templates/with_bom.haml +1 -0
  75. data/test/temple_line_counter_test.rb +40 -0
  76. data/test/test_helper.rb +26 -12
  77. data/test/util_test.rb +6 -47
  78. metadata +88 -106
  79. data/lib/haml/helpers/rails_323_textarea_fix.rb +0 -24
  80. data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
  81. data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
  82. data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
  83. data/test/gemfiles/Gemfile.rails-master +0 -4
  84. data/test/templates/_av_partial_1_ugly.haml +0 -9
  85. data/test/templates/_av_partial_2_ugly.haml +0 -5
  86. data/test/templates/action_view_ugly.haml +0 -47
  87. data/test/templates/standard_ugly.haml +0 -43
data/lib/haml/buffer.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Haml
2
3
  # This class is used only internally. It holds the buffer of HTML that
3
4
  # is eventually output as the resulting document.
@@ -90,15 +91,14 @@ module Haml
90
91
  def initialize(upper = nil, options = {})
91
92
  @active = true
92
93
  @upper = upper
93
- @options = options
94
+ @options = Options.buffer_defaults
95
+ @options = @options.merge(options) unless options.empty?
94
96
  @buffer = new_encoded_string
95
97
  @tabulation = 0
96
98
 
97
99
  # The number of tabs that Engine thinks we should have
98
100
  # @real_tabs + @tabulation is the number of tabs actually output
99
101
  @real_tabs = 0
100
-
101
- @preserve_pattern = /<[\s]*#{@options[:preserve].join("|")}/i
102
102
  end
103
103
 
104
104
  # Appends text to the buffer, properly tabulated.
@@ -117,8 +117,8 @@ module Haml
117
117
  text.sub!(tabs, '') if dont_tab_up
118
118
  end
119
119
 
120
- @buffer << text
121
120
  @real_tabs += tab_change
121
+ @buffer << text
122
122
  end
123
123
 
124
124
  # Modifies the indentation of the document.
@@ -129,82 +129,13 @@ module Haml
129
129
  @real_tabs += tab_change
130
130
  end
131
131
 
132
- Haml::Util.def_static_method(self, :format_script, [:result],
133
- :preserve_script, :in_tag, :preserve_tag, :escape_html,
134
- :nuke_inner_whitespace, :interpolated, :ugly, <<RUBY)
135
- <% # Escape HTML here so that the safety of the string is preserved in Rails
136
- result_name = escape_html ? "html_escape(result.to_s)" : "result.to_s" %>
137
- <% unless ugly %>
138
- # If we're interpolated,
139
- # then the custom tabulation is handled in #push_text.
140
- # The easiest way to avoid it here is to reset @tabulation.
141
- <% if interpolated %>
142
- old_tabulation = @tabulation
143
- @tabulation = 0
144
- <% end %>
145
-
146
- <% if !(in_tag && preserve_tag && !nuke_inner_whitespace) %>
147
- tabulation = @real_tabs
148
- <% end %>
149
- result = <%= result_name %>.<% if nuke_inner_whitespace %>strip<% else %>rstrip<% end %>
150
- <% else %>
151
- result = <%= result_name %><% if nuke_inner_whitespace %>.strip<% end %>
152
- <% end %>
153
-
154
- <% if preserve_tag %>
155
- result = Haml::Helpers.preserve(result)
156
- <% elsif preserve_script %>
157
- result = Haml::Helpers.find_and_preserve(result, options[:preserve])
158
- <% end %>
159
-
160
- <% if ugly %>
161
- return result
162
- <% else %>
163
-
164
- return result if self.instance_variable_get(:@preserve_pattern).match(result)
165
-
166
- <% if !(in_tag && preserve_tag && !nuke_inner_whitespace) %>
167
- has_newline = result.include?("\\n")
168
- <% end %>
169
-
170
- <% if in_tag && !nuke_inner_whitespace %>
171
- <% unless preserve_tag %> if !has_newline <% end %>
172
- @real_tabs -= 1
173
- <% if interpolated %> @tabulation = old_tabulation <% end %>
174
- return result
175
- <% unless preserve_tag %> end <% end %>
176
- <% end %>
177
-
178
- <% if !(in_tag && preserve_tag && !nuke_inner_whitespace) %>
179
- # Precompiled tabulation may be wrong
180
- <% if !interpolated && !in_tag %>
181
- result = tabs + result if @tabulation > 0
182
- <% end %>
183
-
184
- if has_newline
185
- result = result.gsub "\\n", "\\n" + tabs(tabulation)
186
-
187
- # Add tabulation if it wasn't precompiled
188
- <% if in_tag && !nuke_inner_whitespace %> result = tabs(tabulation) + result <% end %>
189
- end
190
-
191
- <% if in_tag && !nuke_inner_whitespace %>
192
- result = "\\n\#{result}\\n\#{tabs(tabulation-1)}"
193
- @real_tabs -= 1
194
- <% end %>
195
- <% if interpolated %> @tabulation = old_tabulation <% end %>
196
- result
197
- <% end %>
198
- <% end %>
199
- RUBY
200
-
201
132
  def attributes(class_id, obj_ref, *attributes_hashes)
202
133
  attributes = class_id
203
134
  attributes_hashes.each do |old|
204
- self.class.merge_attrs(attributes, Hash[old.map {|k, v| [k.to_s, v]}])
135
+ AttributeBuilder.merge_attributes!(attributes, Hash[old.map {|k, v| [k.to_s, v]}])
205
136
  end
206
- self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref
207
- Compiler.build_attributes(
137
+ AttributeBuilder.merge_attributes!(attributes, parse_object_ref(obj_ref)) if obj_ref
138
+ AttributeBuilder.build_attributes(
208
139
  html?, @options[:attr_wrapper], @options[:escape_attrs], @options[:hyphenate_data_attrs], attributes)
209
140
  end
210
141
 
@@ -219,58 +150,35 @@ RUBY
219
150
  buffer << buffer.slice!(capture_position..-1).rstrip
220
151
  end
221
152
 
222
- # Merges two attribute hashes.
223
- # This is the same as `to.merge!(from)`,
224
- # except that it merges id, class, and data attributes.
225
- #
226
- # ids are concatenated with `"_"`,
227
- # and classes are concatenated with `" "`.
228
- # data hashes are simply merged.
153
+ # Works like #{find_and_preserve}, but allows the first newline after a
154
+ # preserved opening tag to remain unencoded, and then outdents the content.
155
+ # This change was motivated primarily by the change in Rails 3.2.3 to emit
156
+ # a newline after textarea helpers.
229
157
  #
230
- # Destructively modifies both `to` and `from`.
231
- #
232
- # @param to [{String => String}] The attribute hash to merge into
233
- # @param from [{String => #to_s}] The attribute hash to merge from
234
- # @return [{String => String}] `to`, after being merged
235
- def self.merge_attrs(to, from)
236
- from['id'] = Compiler.filter_and_join(from['id'], '_') if from['id']
237
- if to['id'] && from['id']
238
- to['id'] << '_' << from.delete('id').to_s
239
- elsif to['id'] || from['id']
240
- from['id'] ||= to['id']
241
- end
242
-
243
- from['class'] = Compiler.filter_and_join(from['class'], ' ') if from['class']
244
- if to['class'] && from['class']
245
- # Make sure we don't duplicate class names
246
- from['class'] = (from['class'].to_s.split(' ') | to['class'].split(' ')).sort.join(' ')
247
- elsif to['class'] || from['class']
248
- from['class'] ||= to['class']
158
+ # @param input [String] The text to process
159
+ # @since Haml 4.0.1
160
+ # @private
161
+ def fix_textareas!(input)
162
+ return input unless toplevel? && input.include?('<textarea'.freeze)
163
+
164
+ pattern = /<(textarea)([^>]*)>(\n|&#x000A;)(.*?)<\/textarea>/im
165
+ input.gsub!(pattern) do |s|
166
+ match = pattern.match(s)
167
+ content = match[4]
168
+ if match[3] == '&#x000A;'
169
+ content.sub!(/\A /, '&#x0020;')
170
+ else
171
+ content.sub!(/\A[ ]*/, '')
172
+ end
173
+ "<#{match[1]}#{match[2]}>\n#{content}</#{match[1]}>"
249
174
  end
250
-
251
- from_data = from.delete('data') || {}
252
- to_data = to.delete('data') || {}
253
-
254
- # forces to_data & from_data into a hash
255
- from_data = { nil => from_data } unless from_data.is_a?(Hash)
256
- to_data = { nil => to_data } unless to_data.is_a?(Hash)
257
-
258
- merged_data = to_data.merge(from_data)
259
-
260
- to['data'] = merged_data unless merged_data.empty?
261
- to.merge!(from)
175
+ input
262
176
  end
263
177
 
264
178
  private
265
179
 
266
- if RUBY_VERSION < "1.9"
267
- def new_encoded_string
268
- ""
269
- end
270
- else
271
- def new_encoded_string
272
- "".encode(Encoding.find(options[:encoding]))
273
- end
180
+ def new_encoded_string
181
+ "".encode(options[:encoding])
274
182
  end
275
183
 
276
184
  @@tab_cache = {}
@@ -308,18 +216,20 @@ RUBY
308
216
  id = "#{ prefix }_#{ id }"
309
217
  end
310
218
 
311
- {'id' => id, 'class' => class_name}
219
+ { 'id'.freeze => id, 'class'.freeze => class_name }
312
220
  end
313
221
 
314
222
  # Changes a word from camel case to underscores.
315
223
  # Based on the method of the same name in Rails' Inflector,
316
224
  # but copied here so it'll run properly without Rails.
317
225
  def underscore(camel_cased_word)
318
- camel_cased_word.to_s.gsub(/::/, '_').
319
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
320
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
321
- tr("-", "_").
322
- downcase
226
+ word = camel_cased_word.to_s.dup
227
+ word.gsub!(/::/, '_')
228
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
229
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
230
+ word.tr!('-', '_')
231
+ word.downcase!
232
+ word
323
233
  end
324
234
  end
325
235
  end