haml-edge 2.3.209 → 2.3.210

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 (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 ''