haml-edge 2.3.209 → 2.3.210

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/.yardopts +2 -0
  2. data/EDGE_GEM_VERSION +1 -1
  3. data/Rakefile +24 -2
  4. data/VERSION +1 -1
  5. data/lib/haml/exec.rb +11 -4
  6. data/lib/haml/filters.rb +3 -0
  7. data/lib/haml/helpers/action_view_extensions.rb +4 -2
  8. data/lib/haml/helpers/action_view_mods.rb +6 -4
  9. data/lib/haml/helpers.rb +2 -10
  10. data/lib/haml/html.rb +0 -1
  11. data/lib/haml/precompiler.rb +37 -30
  12. data/lib/haml/railtie.rb +6 -2
  13. data/lib/haml/root.rb +4 -0
  14. data/lib/haml/template.rb +2 -0
  15. data/lib/haml/util/subset_map.rb +101 -0
  16. data/lib/haml/util.rb +74 -0
  17. data/lib/haml.rb +5 -2
  18. data/lib/sass/engine.rb +36 -31
  19. data/lib/sass/files.rb +1 -1
  20. data/lib/sass/plugin/staleness_checker.rb +9 -9
  21. data/lib/sass/plugin.rb +21 -0
  22. data/lib/sass/script/color.rb +4 -3
  23. data/lib/sass/script/css_lexer.rb +11 -1
  24. data/lib/sass/script/css_parser.rb +4 -1
  25. data/lib/sass/script/funcall.rb +9 -0
  26. data/lib/sass/script/interpolation.rb +21 -0
  27. data/lib/sass/script/lexer.rb +30 -13
  28. data/lib/sass/script/node.rb +1 -1
  29. data/lib/sass/script/number.rb +4 -5
  30. data/lib/sass/script/parser.rb +13 -14
  31. data/lib/sass/script/string.rb +8 -2
  32. data/lib/sass/script/string_interpolation.rb +27 -4
  33. data/lib/sass/script.rb +1 -2
  34. data/lib/sass/scss/css_parser.rb +5 -3
  35. data/lib/sass/scss/parser.rb +146 -64
  36. data/lib/sass/scss/rx.rb +9 -1
  37. data/lib/sass/scss/sass_parser.rb +11 -0
  38. data/lib/sass/scss/script_lexer.rb +2 -0
  39. data/lib/sass/scss/static_parser.rb +48 -0
  40. data/lib/sass/scss.rb +3 -0
  41. data/lib/sass/selector/abstract_sequence.rb +40 -0
  42. data/lib/sass/selector/comma_sequence.rb +80 -0
  43. data/lib/sass/selector/sequence.rb +194 -0
  44. data/lib/sass/selector/simple.rb +107 -0
  45. data/lib/sass/selector/simple_sequence.rb +161 -0
  46. data/lib/sass/selector.rb +353 -0
  47. data/lib/sass/tree/comment_node.rb +1 -0
  48. data/lib/sass/tree/debug_node.rb +1 -0
  49. data/lib/sass/tree/directive_node.rb +1 -0
  50. data/lib/sass/tree/extend_node.rb +60 -0
  51. data/lib/sass/tree/for_node.rb +1 -0
  52. data/lib/sass/tree/if_node.rb +2 -0
  53. data/lib/sass/tree/import_node.rb +2 -0
  54. data/lib/sass/tree/mixin_def_node.rb +1 -0
  55. data/lib/sass/tree/mixin_node.rb +21 -5
  56. data/lib/sass/tree/node.rb +59 -12
  57. data/lib/sass/tree/prop_node.rb +20 -21
  58. data/lib/sass/tree/root_node.rb +8 -17
  59. data/lib/sass/tree/rule_node.rb +49 -100
  60. data/lib/sass/tree/variable_node.rb +1 -0
  61. data/lib/sass/tree/warn_node.rb +1 -0
  62. data/lib/sass/tree/while_node.rb +1 -0
  63. data/lib/sass.rb +1 -0
  64. data/test/haml/engine_test.rb +185 -3
  65. data/test/haml/helper_test.rb +25 -2
  66. data/test/haml/template_test.rb +2 -2
  67. data/test/haml/templates/helpers.haml +13 -0
  68. data/test/haml/util/subset_map_test.rb +91 -0
  69. data/test/haml/util_test.rb +25 -0
  70. data/test/sass/conversion_test.rb +23 -3
  71. data/test/sass/engine_test.rb +50 -7
  72. data/test/sass/extend_test.rb +1045 -0
  73. data/test/sass/results/complex.css +0 -1
  74. data/test/sass/results/script.css +1 -1
  75. data/test/sass/script_conversion_test.rb +16 -0
  76. data/test/sass/script_test.rb +37 -4
  77. data/test/sass/scss/css_test.rb +17 -3
  78. data/test/sass/scss/rx_test.rb +1 -1
  79. data/test/sass/scss/scss_test.rb +30 -0
  80. data/test/sass/templates/complex.sass +0 -2
  81. data/test/test_helper.rb +5 -0
  82. metadata +17 -3
@@ -68,28 +68,19 @@ module Sass::Tree
68
68
  # This only applies for old-style properties with no value,
69
69
  # so returns the empty string if this is new-style.
70
70
  #
71
- # This should only be called once \{#perform} has been called.
72
- #
73
71
  # @return [String] The message
74
72
  def pseudo_class_selector_message
75
- return "" if @prop_syntax == :new || !resolved_value.empty?
73
+ return "" if @prop_syntax == :new || !value.is_a?(Sass::Script::String) || !value.value.empty?
76
74
  "\nIf #{declaration.dump} should be a selector, use \"\\#{declaration}\" instead."
77
75
  end
78
76
 
79
77
  protected
80
78
 
79
+ # @see Node#to_src
81
80
  def to_src(tabs, opts, fmt)
82
- name = self.name.map {|n| n.is_a?(String) ? n : "\#{#{n.to_sass(opts)}}"}.join
83
- if name[0] == ?:
84
- raise Sass::SyntaxError.new("The \":#{name}: #{self.class.val_to_sass(value, opts)}\" hack is not allowed in the Sass indented syntax")
85
- end
86
-
87
- old = opts[:old] && fmt == :sass
88
- initial = old ? ':' : ''
89
- mid = old ? '' : ':'
90
- res = "#{' ' * tabs}#{initial}#{name}#{mid} #{self.class.val_to_sass(value, opts)}"
81
+ res = declaration(tabs, opts, fmt)
91
82
  return res + "#{semi fmt}\n" if children.empty?
92
- res.rstrip + children_to_src(tabs, opts, fmt).rstrip + semi(fmt) + "\n"
83
+ res + children_to_src(tabs, opts, fmt).rstrip + semi(fmt) + "\n"
93
84
  end
94
85
 
95
86
  # Computes the CSS for the property.
@@ -103,10 +94,12 @@ module Sass::Tree
103
94
 
104
95
  # Converts nested properties into flat properties.
105
96
  #
97
+ # @param extends [Haml::Util::SubsetMap{Selector::Simple => Selector::Sequence}]
98
+ # The extensions defined for this tree
106
99
  # @param parent [PropNode, nil] The parent node of this node,
107
100
  # or nil if the parent isn't a {PropNode}
108
101
  # @raise [Sass::SyntaxError] if the property uses invalid syntax
109
- def _cssize(parent)
102
+ def _cssize(extends, parent)
110
103
  node = super
111
104
  result = node.children.dup
112
105
  if !node.resolved_value.empty? || node.children.empty?
@@ -119,9 +112,11 @@ module Sass::Tree
119
112
  # Updates the name and indentation of this node based on the parent name
120
113
  # and nesting level.
121
114
  #
115
+ # @param extends [Haml::Util::SubsetMap{Selector::Simple => Selector::Sequence}]
116
+ # The extensions defined for this tree
122
117
  # @param parent [PropNode, nil] The parent node of this node,
123
118
  # or nil if the parent isn't a {PropNode}
124
- def cssize!(parent)
119
+ def cssize!(extends, parent)
125
120
  self.resolved_name = "#{parent.resolved_name}-#{resolved_name}" if parent
126
121
  self.tabs = parent.tabs + (parent.resolved_value.empty? ? 0 : 1) if parent && style == :nested
127
122
  super
@@ -169,12 +164,16 @@ module Sass::Tree
169
164
  end
170
165
  end
171
166
 
172
- def declaration
173
- if @prop_syntax == :new
174
- "#{resolved_name}: #{resolved_value}"
175
- else
176
- ":#{resolved_name} #{resolved_value}"
177
- end.strip
167
+ def declaration(tabs = 0, opts = {:old => @prop_syntax == :old}, fmt = :sass)
168
+ name = self.name.map {|n| n.is_a?(String) ? n : "\#{#{n.to_sass(opts)}}"}.join
169
+ if name[0] == ?:
170
+ raise Sass::SyntaxError.new("The \":#{name}: #{self.class.val_to_sass(value, opts)}\" hack is not allowed in the Sass indented syntax")
171
+ end
172
+
173
+ old = opts[:old] && fmt == :sass
174
+ initial = old ? ':' : ''
175
+ mid = old ? '' : ':'
176
+ "#{' ' * tabs}#{initial}#{name}#{mid} #{self.class.val_to_sass(value, opts)}".rstrip
178
177
  end
179
178
 
180
179
  class << self
@@ -62,6 +62,7 @@ module Sass
62
62
 
63
63
  protected
64
64
 
65
+ # @see Node#to_src
65
66
  def to_src(opts, fmt)
66
67
  Haml::Util.enum_cons(children + [nil], 2).map do |child, nxt|
67
68
  child.send("to_#{fmt}", 0, opts) +
@@ -75,20 +76,6 @@ module Sass
75
76
  end.join.rstrip + "\n"
76
77
  end
77
78
 
78
- # Destructively converts this static Sass node into a static CSS node,
79
- # and checks that there are no properties at root level.
80
- #
81
- # @param parent [Node, nil] The parent node of this node.
82
- # This should only be non-nil if the parent is the same class as this node
83
- # @see Node#cssize!
84
- def cssize!(parent)
85
- super
86
- return unless child = children.find {|c| c.is_a?(PropNode)}
87
- message = "Properties aren't allowed at the root of a document." +
88
- child.pseudo_class_selector_message
89
- raise Sass::SyntaxError.new(message, :line => child.line)
90
- end
91
-
92
79
  # Computes the CSS corresponding to this Sass tree.
93
80
  #
94
81
  # @param args [Array] ignored
@@ -106,12 +93,16 @@ module Sass
106
93
  return result + "\n"
107
94
  end
108
95
 
109
- # Returns false, because all nodes are allowed at the root of the document
110
- # (properties are detected elsewhere post-mixin-resolution).
96
+ # Returns an error message if the given child node is invalid,
97
+ # and false otherwise.
98
+ #
99
+ # Only property nodes are invalid at root level.
111
100
  #
112
101
  # @see Node#invalid_child?
113
102
  def invalid_child?(child)
114
- false
103
+ return unless child.is_a?(Tree::PropNode)
104
+ "Properties aren't allowed at the root of a document." +
105
+ child.pseudo_class_selector_message
115
106
  end
116
107
  end
117
108
  end
@@ -7,7 +7,6 @@ module Sass::Tree
7
7
  # @see Sass::Tree
8
8
  class RuleNode < Node
9
9
  # The character used to include the parent selector
10
- # @private
11
10
  PARENT = '&'
12
11
 
13
12
  # The CSS selector for this rule,
@@ -18,44 +17,19 @@ module Sass::Tree
18
17
  # @return [Array<String, Sass::Script::Node>]
19
18
  attr_accessor :rule
20
19
 
21
- # The CSS selectors for this rule,
22
- # parsed for commas and parent-references.
20
+ # The CSS selector for this rule,
21
+ # without any unresolved interpolation
22
+ # but with parent references still intact.
23
23
  # It's only set once {Tree::Node#perform} has been called.
24
24
  #
25
- # It's an array of arrays.
26
- # The first level of arrays comma-separated selectors;
27
- # the second represents structure within those selectors,
28
- # currently only parent-refs (represented by `:parent`).
29
- # Newlines are represented as literal `\n` characters in the strings.
30
- # For example,
31
- #
32
- # &.foo, bar, baz,
33
- # bip, &.bop, bup
34
- #
35
- # would be
36
- #
37
- # [[:parent, ".foo"], ["bar"], ["baz"],
38
- # ["\nbip"], [:parent, ".bop"], ["bup"]]
39
- #
40
- # @return [Array<Array<String, Symbol>>]
25
+ # @return [Selector::CommaSequence]
41
26
  attr_accessor :parsed_rules
42
27
 
43
- # The CSS selectors for this rule,
44
- # with all nesting and parent references resolved.
28
+ # The CSS selector for this rule,
29
+ # without any unresolved interpolation or parent references.
45
30
  # It's only set once {Tree::Node#cssize} has been called.
46
31
  #
47
- # Each element is a distinct selector, separated by commas.
48
- # Newlines are represented as literal `\n` characters in the strings.
49
- # For example,
50
- #
51
- # foo bar, baz,
52
- # bang, bip bop, blip
53
- #
54
- # would be
55
- #
56
- # ["foo bar", "baz", "\nbang", "bip bop", "blip"]
57
- #
58
- # @return [Array<String>]
32
+ # @return [Selector::CommaSequence]
59
33
  attr_accessor :resolved_rules
60
34
 
61
35
  # How deep this rule is indented
@@ -121,6 +95,7 @@ module Sass::Tree
121
95
  name.gsub(/^/, ' ' * tabs) + children_to_src(tabs, opts, :sass)
122
96
  end
123
97
 
98
+ # @see Node#to_scss
124
99
  def to_scss(tabs, opts = {})
125
100
  name = rule.map {|r| r.is_a?(String) ? r : "\#{#{r.to_sass(opts)}}"}.
126
101
  join.gsub(/^[ \t]*/, ' ' * tabs)
@@ -135,6 +110,15 @@ module Sass::Tree
135
110
  res
136
111
  end
137
112
 
113
+ # Extends this Rule's selector with the given `extends`.
114
+ #
115
+ # @see Node#do_extend
116
+ def do_extend(extends)
117
+ node = dup
118
+ node.resolved_rules = resolved_rules.do_extend(extends)
119
+ node
120
+ end
121
+
138
122
  protected
139
123
 
140
124
  # Computes the CSS for the rule.
@@ -154,7 +138,9 @@ module Sass::Tree
154
138
  rule_indent = ' ' * (tabs - 1)
155
139
  per_rule_indent, total_indent = [:nested, :expanded].include?(style) ? [rule_indent, ''] : ['', rule_indent]
156
140
 
157
- total_rule = total_indent + resolved_rules.join(rule_separator).split("\n").map do |line|
141
+ total_rule = total_indent + resolved_rules.members.
142
+ map {|seq| seq.to_a.join}.
143
+ join(rule_separator).split("\n").map do |line|
158
144
  per_rule_indent + line.strip
159
145
  end.join(line_separator)
160
146
 
@@ -199,21 +185,24 @@ module Sass::Tree
199
185
  to_return
200
186
  end
201
187
 
202
- # Runs any SassScript that may be embedded in the rule,
203
- # and parses the selectors for commas.
188
+ # Runs SassScript interpolation in the selector,
189
+ # and then parses the result into a {Sass::Selector::CommaSequence}.
204
190
  #
205
191
  # @param environment [Sass::Environment] The lexical environment containing
206
192
  # variable and mixin values
207
193
  def perform!(environment)
208
- @parsed_rules = parse_selector(run_interp(@rule, environment))
194
+ @parsed_rules = Sass::SCSS::StaticParser.new(run_interp(@rule, environment)).
195
+ parse_selector(self.line, self.filename)
209
196
  super
210
197
  end
211
198
 
212
199
  # Converts nested rules into a flat list of rules.
213
200
  #
201
+ # @param extends [Haml::Util::SubsetMap{Selector::Simple => Selector::Sequence}]
202
+ # The extensions defined for this tree
214
203
  # @param parent [RuleNode, nil] The parent node of this node,
215
204
  # or nil if the parent isn't a {RuleNode}
216
- def _cssize(parent)
205
+ def _cssize(extends, parent)
217
206
  node = super
218
207
  rules = node.children.select {|c| c.is_a?(RuleNode)}
219
208
  props = node.children.reject {|c| c.is_a?(RuleNode) || c.invisible?}
@@ -232,14 +221,28 @@ module Sass::Tree
232
221
  # Resolves parent references and nested selectors,
233
222
  # and updates the indentation based on the parent's indentation.
234
223
  #
224
+ # @param extends [Haml::Util::SubsetMap{Selector::Simple => Selector::Sequence}]
225
+ # The extensions defined for this tree
235
226
  # @param parent [RuleNode, nil] The parent node of this node,
236
227
  # or nil if the parent isn't a {RuleNode}
237
228
  # @raise [Sass::SyntaxError] if the rule has no parents but uses `&`
238
- def cssize!(parent)
239
- self.resolved_rules = resolve_parent_refs(parent && parent.resolved_rules)
229
+ def cssize!(extends, parent)
230
+ self.resolved_rules = @parsed_rules.resolve_parent_refs(parent && parent.resolved_rules)
240
231
  super
241
232
  end
242
233
 
234
+ # Returns an error message if the given child node is invalid,
235
+ # and false otherwise.
236
+ #
237
+ # {ExtendNode}s are valid within {RuleNode}s.
238
+ #
239
+ # @param child [Tree::Node] A potential child nodecompact.
240
+ # @return [Boolean, String] Whether or not the child node is valid,
241
+ # as well as the error message to display if it is invalid
242
+ def invalid_child?(child)
243
+ super unless child.is_a?(ExtendNode)
244
+ end
245
+
243
246
  # A hash that will be associated with this rule in the CSS document
244
247
  # if the {file:SASS_REFERENCE.md#debug_info-option `:debug_info` option} is enabled.
245
248
  # This data is used by e.g. [the FireSass Firebug extension](https://addons.mozilla.org/en-US/firefox/addon/103988).
@@ -252,70 +255,16 @@ module Sass::Tree
252
255
 
253
256
  private
254
257
 
255
- def resolve_parent_refs(super_rules)
256
- if super_rules.nil?
257
- return @parsed_rules.map do |rule|
258
- if rule.include?(:parent)
259
- raise Sass::SyntaxError.new("Base-level rules cannot contain the parent-selector-referencing character '#{PARENT}'.")
260
- end
261
-
262
- rule.join
263
- end
264
- end
265
-
266
- new_rules = []
267
- super_rules.each do |super_rule|
268
- @parsed_rules.each do |rule|
269
- new_rules << []
270
-
271
- # An initial newline of the child rule
272
- # should be moved to the beginning of the entire rule
273
- rule.first.slice!(0) if nl = (rule.first.is_a?(String) && rule.first[0] == ?\n)
274
- rule = [nl ? "\n" : "", :parent, " ", *rule] unless rule.include?(:parent)
275
-
276
- new_rules.last << rule.map do |segment|
277
- next segment unless segment == :parent
278
- super_rule
279
- end.join
280
- end
281
- end
282
- new_rules
283
- end
284
-
285
- def parse_selector(text)
286
- scanner = StringScanner.new(text)
287
- rules = [[]]
288
-
289
- while scanner.rest?
290
- rules.last << scanner.scan(/[^",&]*/)
291
- case scanner.scan(/./)
292
- when '&'; rules.last << :parent
293
- when ','
294
- scanner.scan(/\s*/)
295
- if scanner.rest?
296
- rules << []
297
- rules.last << "\n" if scanner.matched.include?("\n")
298
- end
299
- when '"'
300
- rules.last << '"' << scanner.scan(/([^"\\]|\\.)*/)
301
- # We don't want to enforce that strings are closed,
302
- # but we do want to consume quotes or trailing backslashes.
303
- rules.last << scanner.scan(/./) if scanner.rest?
304
- end
305
- end
306
-
307
- rules.map! do |l|
308
- Haml::Util.merge_adjacent_strings(l).reject {|r| r.is_a?(String) && r.empty?}
309
- end
310
-
311
- rules
312
- end
313
-
314
258
  def debug_info_rule
315
259
  node = DirectiveNode.new("@media -sass-debug-info")
316
260
  debug_info.map {|k, v| [k.to_s, v.to_s]}.sort.each do |k, v|
317
261
  rule = RuleNode.new([""])
318
- rule.resolved_rules = [[k.to_s.gsub(/[^\w-]/, "\\\\\\0")]]
262
+ rule.resolved_rules = Sass::Selector::CommaSequence.new(
263
+ [Sass::Selector::Sequence.new(
264
+ [Sass::Selector::SimpleSequence.new(
265
+ [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)])
266
+ ])
267
+ ])
319
268
  prop = PropNode.new([""], "", :new)
320
269
  prop.resolved_name = "font-family"
321
270
  prop.resolved_value = Sass::SCSS::RX.escape_ident(v.to_s)
@@ -16,6 +16,7 @@ module Sass
16
16
 
17
17
  protected
18
18
 
19
+ # @see Node#to_src
19
20
  def to_src(tabs, opts, fmt)
20
21
  "#{' ' * tabs}$#{dasherize(@name, opts)}: #{@expr.to_sass(opts)}#{' !default' if @guarded}#{semi fmt}\n"
21
22
  end
@@ -12,6 +12,7 @@ module Sass
12
12
 
13
13
  protected
14
14
 
15
+ # @see Node#to_src
15
16
  def to_src(tabs, opts, fmt)
16
17
  "#{' ' * tabs}@warn #{@expr.to_sass(opts)}#{semi fmt}\n"
17
18
  end
@@ -13,6 +13,7 @@ module Sass::Tree
13
13
 
14
14
  protected
15
15
 
16
+ # @see Node#to_src
16
17
  def to_src(tabs, opts, fmt)
17
18
  "#{' ' * tabs}@while #{@expr.to_sass(opts)}" + children_to_src(tabs, opts, fmt)
18
19
  end
data/lib/sass.rb CHANGED
@@ -16,6 +16,7 @@ module Sass
16
16
 
17
17
  # A string representing the version of Sass.
18
18
  # A more fine-grained representation is available from {Haml::Version#version Sass.version}.
19
+ # @api public
19
20
  VERSION = version[:string] unless defined?(Sass::VERSION)
20
21
  end
21
22
 
@@ -1348,17 +1348,199 @@ SASS
1348
1348
  render("%a{:a => 'b',\n:b => 'c'}(c='d'\nd='e') bar"))
1349
1349
  end
1350
1350
 
1351
+ # Ruby Multiline
1352
+
1353
+ def test_silent_ruby_multiline
1354
+ assert_equal(<<HTML, render(<<HAML))
1355
+ bar, baz, bang
1356
+ <p>foo</p>
1357
+ HTML
1358
+ - foo = ["bar",
1359
+ "baz",
1360
+ "bang"]
1361
+ = foo.join(", ")
1362
+ %p foo
1363
+ HAML
1364
+ end
1365
+
1366
+ def test_loud_ruby_multiline
1367
+ assert_equal(<<HTML, render(<<HAML))
1368
+ bar, baz, bang
1369
+ <p>foo</p>
1370
+ <p>bar</p>
1371
+ HTML
1372
+ = ["bar",
1373
+ "baz",
1374
+ "bang"].join(", ")
1375
+ %p foo
1376
+ %p bar
1377
+ HAML
1378
+ end
1379
+
1380
+ def test_escaped_loud_ruby_multiline
1381
+ assert_equal(<<HTML, render(<<HAML))
1382
+ bar&lt;, baz, bang
1383
+ <p>foo</p>
1384
+ <p>bar</p>
1385
+ HTML
1386
+ &= ["bar<",
1387
+ "baz",
1388
+ "bang"].join(", ")
1389
+ %p foo
1390
+ %p bar
1391
+ HAML
1392
+ end
1393
+
1394
+ def test_unescaped_loud_ruby_multiline
1395
+ assert_equal(<<HTML, render(<<HAML, :escape_html => true))
1396
+ bar<, baz, bang
1397
+ <p>foo</p>
1398
+ <p>bar</p>
1399
+ HTML
1400
+ != ["bar<",
1401
+ "baz",
1402
+ "bang"].join(", ")
1403
+ %p foo
1404
+ %p bar
1405
+ HAML
1406
+ end
1407
+
1408
+ def test_flattened_loud_ruby_multiline
1409
+ assert_equal(<<HTML, render(<<HAML))
1410
+ <pre>bar&#x000A;baz&#x000A;bang</pre>
1411
+ <p>foo</p>
1412
+ <p>bar</p>
1413
+ HTML
1414
+ ~ "<pre>" + ["bar",
1415
+ "baz",
1416
+ "bang"].join("\\n") + "</pre>"
1417
+ %p foo
1418
+ %p bar
1419
+ HAML
1420
+ end
1421
+
1422
+ def test_loud_ruby_multiline_with_block
1423
+ assert_equal(<<HTML, render(<<HAML))
1424
+ farfazfang
1425
+ <p>foo</p>
1426
+ <p>bar</p>
1427
+ HTML
1428
+ = ["bar",
1429
+ "baz",
1430
+ "bang"].map do |str|
1431
+ - str.gsub("ba",
1432
+ "fa")
1433
+ %p foo
1434
+ %p bar
1435
+ HAML
1436
+ end
1437
+
1438
+ def test_silent_ruby_multiline_with_block
1439
+ assert_equal(<<HTML, render(<<HAML))
1440
+ far
1441
+ faz
1442
+ fang
1443
+ <p>foo</p>
1444
+ <p>bar</p>
1445
+ HTML
1446
+ - ["bar",
1447
+ "baz",
1448
+ "bang"].map do |str|
1449
+ = str.gsub("ba",
1450
+ "fa")
1451
+ %p foo
1452
+ %p bar
1453
+ HAML
1454
+ end
1455
+
1456
+ def test_ruby_multiline_in_tag
1457
+ assert_equal(<<HTML, render(<<HAML))
1458
+ <p>foo, bar, baz</p>
1459
+ <p>foo</p>
1460
+ <p>bar</p>
1461
+ HTML
1462
+ %p= ["foo",
1463
+ "bar",
1464
+ "baz"].join(", ")
1465
+ %p foo
1466
+ %p bar
1467
+ HAML
1468
+ end
1469
+
1470
+ def test_escaped_ruby_multiline_in_tag
1471
+ assert_equal(<<HTML, render(<<HAML))
1472
+ <p>foo&lt;, bar, baz</p>
1473
+ <p>foo</p>
1474
+ <p>bar</p>
1475
+ HTML
1476
+ %p&= ["foo<",
1477
+ "bar",
1478
+ "baz"].join(", ")
1479
+ %p foo
1480
+ %p bar
1481
+ HAML
1482
+ end
1483
+
1484
+ def test_unescaped_ruby_multiline_in_tag
1485
+ assert_equal(<<HTML, render(<<HAML, :escape_html => true))
1486
+ <p>foo<, bar, baz</p>
1487
+ <p>foo</p>
1488
+ <p>bar</p>
1489
+ HTML
1490
+ %p!= ["foo<",
1491
+ "bar",
1492
+ "baz"].join(", ")
1493
+ %p foo
1494
+ %p bar
1495
+ HAML
1496
+ end
1497
+
1498
+ def test_ruby_multiline_with_normal_multiline
1499
+ assert_equal(<<HTML, render(<<HAML))
1500
+ foobarbar, baz, bang
1501
+ <p>foo</p>
1502
+ <p>bar</p>
1503
+ HTML
1504
+ = "foo" + |
1505
+ "bar" + |
1506
+ ["bar", |
1507
+ "baz",
1508
+ "bang"].join(", ")
1509
+ %p foo
1510
+ %p bar
1511
+ HAML
1512
+ end
1513
+
1514
+ def test_ruby_multiline_after_filter
1515
+ assert_equal(<<HTML, render(<<HAML))
1516
+ foo
1517
+ bar
1518
+ bar, baz, bang
1519
+ <p>foo</p>
1520
+ <p>bar</p>
1521
+ HTML
1522
+ :plain
1523
+ foo
1524
+ bar
1525
+ = ["bar",
1526
+ "baz",
1527
+ "bang"].join(", ")
1528
+ %p foo
1529
+ %p bar
1530
+ HAML
1531
+ end
1532
+
1351
1533
  # Encodings
1352
1534
 
1353
1535
  def test_utf_8_bom
1354
- assert_equal <<CSS, render(<<SCSS)
1536
+ assert_equal <<HTML, render(<<HAML)
1355
1537
  <div class='foo'>
1356
1538
  <p>baz</p>
1357
1539
  </div>
1358
- CSS
1540
+ HTML
1359
1541
  \xEF\xBB\xBF.foo
1360
1542
  %p baz
1361
- SCSS
1543
+ HAML
1362
1544
  end
1363
1545
 
1364
1546
  unless Haml::Util.ruby1_8?
@@ -15,7 +15,18 @@ module Haml::Helpers
15
15
  end
16
16
 
17
17
  class HelperTest < Test::Unit::TestCase
18
- Post = Struct.new('Post', :body)
18
+ Post = Struct.new('Post', :body, :error_field, :errors)
19
+ class PostErrors
20
+ def on(name)
21
+ return unless name == 'error_field'
22
+ ["Really bad error"]
23
+ end
24
+ alias_method :full_messages, :on
25
+
26
+ def [](name)
27
+ on(name) || []
28
+ end
29
+ end
19
30
 
20
31
  def setup
21
32
  @base = ActionView::Base.new
@@ -26,7 +37,7 @@ class HelperTest < Test::Unit::TestCase
26
37
  @base.controller.response = ActionController::Response.new
27
38
  end
28
39
 
29
- @base.instance_variable_set('@post', Post.new("Foo bar\nbaz"))
40
+ @base.instance_variable_set('@post', Post.new("Foo bar\nbaz", nil, PostErrors.new))
30
41
  end
31
42
 
32
43
  def render(text, options = {})
@@ -153,6 +164,18 @@ HTML
153
164
  HAML
154
165
  end
155
166
 
167
+ def test_content_tag_error_wrapping
168
+ def @base.protect_against_forgery?; false; end
169
+ assert_equal(<<HTML, render(<<HAML, :action_view))
170
+ <form action="" method="post">
171
+ <div class="fieldWithErrors"><label for="post_error_field">Error field</label></div>
172
+ </form>
173
+ HTML
174
+ #{rails_block_helper_char} form_for #{form_for_calling_convention('post')}, :url => '' do |f|
175
+ = f.label 'error_field'
176
+ HAML
177
+ end
178
+
156
179
  def test_haml_tag_name_attribute_with_id
157
180
  assert_equal("<p id='some_id'></p>\n", render("- haml_tag 'p#some_id'"))
158
181
  end
@@ -288,7 +288,7 @@ END
288
288
  <input id="article_body" name="article[body]" size="30" type="text" value="World" />
289
289
  </form>
290
290
  HTML
291
- - form_for :article, @article, :url => '' do |f|
291
+ - form_for #{form_for_calling_convention(:article)}, :url => '' do |f|
292
292
  Title:
293
293
  = f.text_field :title
294
294
  Body:
@@ -387,7 +387,7 @@ HAML
387
387
  <input id="article_body" name="article[body]" size="30" type="text" value="World" />
388
388
  </form>
389
389
  HTML
390
- #{rails_block_helper_char} form_for :article, @article, :url => '' do |f|
390
+ #{rails_block_helper_char} form_for #{form_for_calling_convention(:article)}, :url => '' do |f|
391
391
  Title:
392
392
  = f.text_field :title
393
393
  Body:
@@ -62,6 +62,19 @@ click
62
62
  <input id="article_body" name="article[body]" size="30" type="text" value="World" />
63
63
  </form>
64
64
  </div>
65
+ - elsif Haml::Util.ap_geq_3_beta_3?
66
+ %p
67
+ = form_tag ''
68
+ %div
69
+ = form_tag '' do
70
+ %div= submit_tag 'save'
71
+ - @foo = 'value one'
72
+ = test_partial 'partial'
73
+ = form_for @article, :as => :article, :url => '', :html => {:class => nil, :id => nil} do |f|
74
+ Title:
75
+ = f.text_field :title
76
+ Body:
77
+ = f.text_field :body
65
78
  - elsif Haml::Util.ap_geq_3?
66
79
  %p
67
80
  = form_tag ''