sass 3.2.0.alpha.261 → 3.2.0.alpha.268

Sign up to get free protection for your applications and to get access to all the features.
data/REVISION CHANGED
@@ -1 +1 @@
1
- fe4e2a9b7d9b0cc0eceb20e97dc43875258d6424
1
+ bdee97a283eb9a69301f0bd60e8dc28db78517c3
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0.alpha.261
1
+ 3.2.0.alpha.268
@@ -683,8 +683,9 @@ WARNING
683
683
  raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
684
684
  raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
685
685
  :line => @line + 1) unless line.children.empty?
686
+ optional = !!value.gsub!(/\s+#{Sass::SCSS::RX::OPTIONAL}$/, '')
686
687
  offset = line.offset + line.text.index(value).to_i
687
- Tree::ExtendNode.new(parse_interp(value, offset))
688
+ Tree::ExtendNode.new(parse_interp(value, offset), optional)
688
689
  when 'warn'
689
690
  raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
690
691
  raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath warn directives.",
@@ -25,14 +25,14 @@ module Less
25
25
  sel = selector_str(path)
26
26
  base = selector_str(selector_base(path))
27
27
  if base == sel
28
- env << Node::SassNode.new(Sass::Tree::ExtendNode.new([sel]))
28
+ env << Node::SassNode.new(Sass::Tree::ExtendNode.new([sel], false))
29
29
  else
30
30
  Sass::Util.sass_warn <<WARNING
31
31
  WARNING: Sass doesn't support mixing in selector sequences.
32
32
  Replacing "#{sel}" with "@extend #{base}"
33
33
  WARNING
34
34
  env << Node::SassNode.new(Sass::Tree::CommentNode.new(["// #{sel};"], :silent))
35
- env << Node::SassNode.new(Sass::Tree::ExtendNode.new([base]))
35
+ env << Node::SassNode.new(Sass::Tree::ExtendNode.new([base], false))
36
36
  end
37
37
  end
38
38
  end
@@ -289,7 +289,10 @@ module Sass
289
289
  end
290
290
 
291
291
  def extend_directive
292
- node(Sass::Tree::ExtendNode.new(expr!(:selector_sequence)))
292
+ selector = expr!(:selector_sequence)
293
+ optional = tok(OPTIONAL)
294
+ ss
295
+ node(Sass::Tree::ExtendNode.new(selector, !!optional))
293
296
  end
294
297
 
295
298
  def import_directive
@@ -118,6 +118,7 @@ module Sass
118
118
  HEXCOLOR = /\#[0-9a-fA-F]+/
119
119
  INTERP_START = /#\{/
120
120
  ANY = /:(-[-\w]+-)?any\(/i
121
+ OPTIONAL = /!#{W}optional/i
121
122
 
122
123
  IDENT_HYPHEN_INTERP = /-(#\{)/
123
124
  STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|\\#{NL}|#{ESCAPE})*)\"/
@@ -102,7 +102,9 @@ module Sass
102
102
  # seq is A, sels is B, and self is C
103
103
 
104
104
  self_without_sel = self.members - sels
105
+ group.each {|e, _| e.result = :failed_to_unify}
105
106
  next unless unified = seq.members.last.unify(self_without_sel, subject?)
107
+ group.each {|e, _| e.result = :succeeded}
106
108
  next if group.map {|e, _| check_directives_match!(e, parent_directives)}.none?
107
109
  new_seq = Sequence.new(seq.members[0...-1] + [unified])
108
110
  new_seq.add_sources!(sources + [seq])
@@ -17,12 +17,19 @@ module Sass::Tree
17
17
  # @return [Array<String, Sass::Script::Node>]
18
18
  attr_accessor :selector
19
19
 
20
+ # Whether the `@extend` is allowed to match no selectors or not.
21
+ #
22
+ # @return [Boolean]
23
+ def optional?; @optional; end
24
+
20
25
  # @param selector [Array<String, Sass::Script::Node>]
21
26
  # The CSS selector to extend,
22
27
  # interspersed with {Sass::Script::Node}s
23
28
  # representing `#{}`-interpolation.
24
- def initialize(selector)
29
+ # @param optional [Boolean] See \{#optional}
30
+ def initialize(selector, optional)
25
31
  @selector = selector
32
+ @optional = optional
26
33
  super()
27
34
  end
28
35
  end
@@ -109,7 +109,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
109
109
  end
110
110
 
111
111
  def visit_extend(node)
112
- "#{tab_str}@extend #{selector_to_src(node.selector).lstrip}#{semi}\n"
112
+ "#{tab_str}@extend #{selector_to_src(node.selector).lstrip}#{semi}#{" !optional" if node.optional?}\n"
113
113
  end
114
114
 
115
115
  def visit_for(node)
@@ -88,13 +88,17 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
88
88
  # single [ExtendNode] can have multiple Extends if either the parent node or
89
89
  # the extended selector is a comma sequence.
90
90
  #
91
- # @attr extender [Array<Sass::Selector::SimpleSequence, String>]
91
+ # @attr extender [Sass::Selector::Sequence]
92
92
  # The selector of the CSS rule containing the `@extend`.
93
93
  # @attr target [Array<Sass::Selector::Simple>] The selector being `@extend`ed.
94
94
  # @attr node [Sass::Tree::ExtendNode] The node that produced this extend.
95
95
  # @attr directives [Array<Sass::Tree::DirectiveNode>]
96
96
  # The directives containing the `@extend`.
97
- Extend = Struct.new(:extender, :target, :node, :directives)
97
+ # @attr result [Symbol]
98
+ # The result of this extend. One of `:not_found` (the target doesn't exist
99
+ # in the document), `:failed_to_unify` (the target exists but cannot be
100
+ # unified with the extender), or `:succeeded`.
101
+ Extend = Struct.new(:extender, :target, :node, :directives, :result)
98
102
 
99
103
  # Registers an extension in the `@extends` subset map.
100
104
  def visit_extend(node)
@@ -116,7 +120,7 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
116
120
  raise Sass::SyntaxError.new("#{seq} can't extend: invalid selector")
117
121
  end
118
122
 
119
- @extends[sel] = Extend.new(seq, sel, node, @parent_directives.dup)
123
+ @extends[sel] = Extend.new(seq, sel, node, @parent_directives.dup, :not_found)
120
124
  end
121
125
  end
122
126
 
@@ -2,6 +2,9 @@
2
2
  #
3
3
  # Destructively modifies the tree.
4
4
  class Sass::Tree::Visitors::Extend < Sass::Tree::Visitors::Base
5
+ # Performs the given extensions on the static CSS tree based in `root`, then
6
+ # validates that all extends matched some selector.
7
+ #
5
8
  # @param root [Tree::Node] The root node of the tree to visit.
6
9
  # @param extends [Sass::Util::SubsetMap{Selector::Simple =>
7
10
  # Sass::Tree::Visitors::Cssize::Extend}]
@@ -10,6 +13,7 @@ class Sass::Tree::Visitors::Extend < Sass::Tree::Visitors::Base
10
13
  def self.visit(root, extends)
11
14
  return if extends.empty?
12
15
  new(extends).send(:visit, root)
16
+ check_extends_fired! extends
13
17
  end
14
18
 
15
19
  protected
@@ -39,4 +43,25 @@ class Sass::Tree::Visitors::Extend < Sass::Tree::Visitors::Base
39
43
  def visit_rule(node)
40
44
  node.resolved_rules = node.resolved_rules.do_extend(@extends, @parent_directives)
41
45
  end
46
+
47
+ private
48
+
49
+ def self.check_extends_fired!(extends)
50
+ extends.each_value do |ex|
51
+ next if ex.result == :succeeded || ex.node.optional?
52
+ warn = "\"#{ex.extender}\" failed to @extend \"#{ex.target}\"."
53
+ reason =
54
+ if ex.result == :not_found
55
+ "The selector \"#{ex.target}\" was not found."
56
+ else
57
+ "No selectors matching \"#{ex.target}\" could be unified with \"#{ex.extender}\"."
58
+ end
59
+
60
+ Sass::Util.sass_warn <<WARN
61
+ WARNING on line #{ex.node.line}#{" of #{ex.node.filename}" if ex.node.filename}: #{warn}
62
+ #{reason}
63
+ This will be an error in future releases of Sass.
64
+ WARN
65
+ end
66
+ end
42
67
  end
@@ -96,6 +96,14 @@ module Sass
96
96
  def [](set)
97
97
  get(set).map {|v, _| v}
98
98
  end
99
+
100
+ # Iterates over each value in the subset map. Ignores keys completely. If
101
+ # multiple keys have the same value, this will return them multiple times.
102
+ #
103
+ # @yield [Object] Each value in the map.
104
+ def each_value
105
+ @vals.each {|v| yield v}
106
+ end
99
107
  end
100
108
  end
101
109
  end
@@ -1552,6 +1552,17 @@ foo bar {
1552
1552
  SCSS
1553
1553
  end
1554
1554
 
1555
+ def test_extend_with_optional
1556
+ assert_scss_to_sass <<SASS, <<SCSS
1557
+ foo
1558
+ @extend .bar !optional
1559
+ SASS
1560
+ foo {
1561
+ @extend .bar !optional;
1562
+ }
1563
+ SCSS
1564
+ end
1565
+
1555
1566
  ## Regression Tests
1556
1567
 
1557
1568
  def test_empty_lists
@@ -152,7 +152,10 @@ SCSS
152
152
  def test_id_unification
153
153
  assert_unification '.foo.bar', '#baz {@extend .foo}', '.foo.bar, .bar#baz'
154
154
  assert_unification '.foo#baz', '#baz {@extend .foo}', '#baz'
155
- assert_unification '.foo#baz', '#bar {@extend .foo}', '.foo#baz'
155
+
156
+ assert_extend_doesnt_match('#bar', '.foo', :failed_to_unify, 2) do
157
+ assert_unification '.foo#baz', '#bar {@extend .foo}', '.foo#baz'
158
+ end
156
159
  end
157
160
 
158
161
  def test_universal_unification_with_simple_target
@@ -175,7 +178,11 @@ SCSS
175
178
  def test_universal_unification_with_namespaced_universal_target
176
179
  assert_unification 'ns|*.foo', '* {@extend .foo}', 'ns|*'
177
180
  assert_unification 'ns|*.foo', '*|* {@extend .foo}', 'ns|*'
178
- assert_unification 'ns1|*.foo', 'ns2|* {@extend .foo}', 'ns1|*.foo'
181
+
182
+ assert_extend_doesnt_match('ns2|*', '.foo', :failed_to_unify, 2) do
183
+ assert_unification 'ns1|*.foo', 'ns2|* {@extend .foo}', 'ns1|*.foo'
184
+ end
185
+
179
186
  assert_unification 'ns|*.foo', 'ns|* {@extend .foo}', 'ns|*'
180
187
  end
181
188
 
@@ -191,7 +198,11 @@ SCSS
191
198
  def test_universal_unification_with_namespaced_element_target
192
199
  assert_unification 'ns|a.foo', '* {@extend .foo}', 'ns|a'
193
200
  assert_unification 'ns|a.foo', '*|* {@extend .foo}', 'ns|a'
194
- assert_unification 'ns1|a.foo', 'ns2|* {@extend .foo}', 'ns1|a.foo'
201
+
202
+ assert_extend_doesnt_match('ns2|*', '.foo', :failed_to_unify, 2) do
203
+ assert_unification 'ns1|a.foo', 'ns2|* {@extend .foo}', 'ns1|a.foo'
204
+ end
205
+
195
206
  assert_unification 'ns|a.foo', 'ns|* {@extend .foo}', 'ns|a'
196
207
  end
197
208
 
@@ -214,7 +225,11 @@ SCSS
214
225
  def test_element_unification_with_namespaced_universal_target
215
226
  assert_unification 'ns|*.foo', 'a {@extend .foo}', 'ns|*.foo, ns|a'
216
227
  assert_unification 'ns|*.foo', '*|a {@extend .foo}', 'ns|*.foo, ns|a'
217
- assert_unification 'ns1|*.foo', 'ns2|a {@extend .foo}', 'ns1|*.foo'
228
+
229
+ assert_extend_doesnt_match('ns2|a', '.foo', :failed_to_unify, 2) do
230
+ assert_unification 'ns1|*.foo', 'ns2|a {@extend .foo}', 'ns1|*.foo'
231
+ end
232
+
218
233
  assert_unification 'ns|*.foo', 'ns|a {@extend .foo}', 'ns|*.foo, ns|a'
219
234
  end
220
235
 
@@ -225,13 +240,20 @@ SCSS
225
240
  assert_unification '*|a.foo', '*|a {@extend .foo}', '*|a'
226
241
  assert_unification 'a.foo', 'ns|a {@extend .foo}', 'a.foo, ns|a'
227
242
  assert_unification '*|a.foo', 'ns|a {@extend .foo}', '*|a.foo, ns|a'
228
- assert_unification 'a.foo', 'h1 {@extend .foo}', 'a.foo'
243
+
244
+ assert_extend_doesnt_match('h1', '.foo', :failed_to_unify, 2) do
245
+ assert_unification 'a.foo', 'h1 {@extend .foo}', 'a.foo'
246
+ end
229
247
  end
230
248
 
231
249
  def test_element_unification_with_namespaced_element_target
232
250
  assert_unification 'ns|a.foo', 'a {@extend .foo}', 'ns|a'
233
251
  assert_unification 'ns|a.foo', '*|a {@extend .foo}', 'ns|a'
234
- assert_unification 'ns1|a.foo', 'ns2|a {@extend .foo}', 'ns1|a.foo'
252
+
253
+ assert_extend_doesnt_match('ns2|a', '.foo', :failed_to_unify, 2) do
254
+ assert_unification 'ns1|a.foo', 'ns2|a {@extend .foo}', 'ns1|a.foo'
255
+ end
256
+
235
257
  assert_unification 'ns|a.foo', 'ns|a {@extend .foo}', 'ns|a'
236
258
  end
237
259
 
@@ -246,8 +268,15 @@ SCSS
246
268
  def test_pseudo_unification
247
269
  assert_unification ':foo.baz', ':foo(2n+1) {@extend .baz}', ':foo.baz, :foo:foo(2n+1)'
248
270
  assert_unification ':foo.baz', '::foo {@extend .baz}', ':foo.baz, :foo::foo'
249
- assert_unification '::foo.baz', '::bar {@extend .baz}', '::foo.baz'
250
- assert_unification '::foo.baz', '::foo(2n+1) {@extend .baz}', '::foo.baz'
271
+
272
+ assert_extend_doesnt_match('::bar', '.baz', :failed_to_unify, 2) do
273
+ assert_unification '::foo.baz', '::bar {@extend .baz}', '::foo.baz'
274
+ end
275
+
276
+ assert_extend_doesnt_match('::foo(2n+1)', '.baz', :failed_to_unify, 2) do
277
+ assert_unification '::foo.baz', '::foo(2n+1) {@extend .baz}', '::foo.baz'
278
+ end
279
+
251
280
  assert_unification '::foo.baz', '::foo {@extend .baz}', '::foo'
252
281
  assert_unification '::foo(2n+1).baz', '::foo(2n+1) {@extend .baz}', '::foo(2n+1)'
253
282
  assert_unification ':foo.baz', ':bar {@extend .baz}', ':foo.baz, :foo:bar'
@@ -318,7 +347,9 @@ SCSS
318
347
  end
319
348
 
320
349
  def test_long_extendee_requires_all_selectors
321
- assert_extends '.foo', '.baz {@extend .foo.bar}', '.foo'
350
+ assert_extend_doesnt_match('.baz', '.foo.bar', :not_found, 2) do
351
+ assert_extends '.foo', '.baz {@extend .foo.bar}', '.foo'
352
+ end
322
353
  end
323
354
 
324
355
  def test_long_extendee_matches_supersets
@@ -340,8 +371,13 @@ SCSS
340
371
  end
341
372
 
342
373
  def test_long_extender_aborts_unification
343
- assert_extends 'a.foo#bar', 'h1.baz {@extend .foo}', 'a.foo#bar'
344
- assert_extends 'a.foo#bar', '.bang#baz {@extend .foo}', 'a.foo#bar'
374
+ assert_extend_doesnt_match('h1.baz', '.foo', :failed_to_unify, 2) do
375
+ assert_extends 'a.foo#bar', 'h1.baz {@extend .foo}', 'a.foo#bar'
376
+ end
377
+
378
+ assert_extend_doesnt_match('.bang#baz', '.foo', :failed_to_unify, 2) do
379
+ assert_extends 'a.foo#bar', '.bang#baz {@extend .foo}', 'a.foo#bar'
380
+ end
345
381
  end
346
382
 
347
383
  ## Nested Extenders
@@ -355,7 +391,9 @@ SCSS
355
391
  end
356
392
 
357
393
  def test_nested_extender_aborts_unification
358
- assert_extends 'baz.foo', 'foo bar {@extend .foo}', 'baz.foo'
394
+ assert_extend_doesnt_match('foo bar', '.foo', :failed_to_unify, 2) do
395
+ assert_extends 'baz.foo', 'foo bar {@extend .foo}', 'baz.foo'
396
+ end
359
397
  end
360
398
 
361
399
  def test_nested_extender_alternates_parents
@@ -771,7 +809,8 @@ SCSS
771
809
  end
772
810
 
773
811
  def test_placeholder_selector_as_modifier
774
- assert_equal <<CSS, render(<<SCSS)
812
+ assert_extend_doesnt_match('div', '%foo', :failed_to_unify, 3) do
813
+ assert_equal <<CSS, render(<<SCSS)
775
814
  a.baz.bar {
776
815
  color: blue; }
777
816
  CSS
@@ -779,6 +818,7 @@ a%foo.baz {color: blue}
779
818
  .bar {@extend %foo}
780
819
  div {@extend %foo}
781
820
  SCSS
821
+ end
782
822
  end
783
823
 
784
824
  def test_placeholder_interpolation
@@ -805,7 +845,7 @@ SCSS
805
845
 
806
846
  def test_extend_out_of_media
807
847
  assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}
808
- DEPRECATION WARNING on line 3 of test_extend_out_of_media_inline.sass:
848
+ DEPRECATION WARNING on line 3 of test_extend_out_of_media_inline.scss:
809
849
  @extending an outer selector from within @media is deprecated.
810
850
  You may only @extend selectors within the same directive.
811
851
  This will be an error in Sass 3.3.
@@ -823,7 +863,7 @@ SCSS
823
863
 
824
864
  def test_extend_out_of_unknown_directive
825
865
  assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}
826
- DEPRECATION WARNING on line 3 of test_extend_out_of_unknown_directive_inline.sass:
866
+ DEPRECATION WARNING on line 3 of test_extend_out_of_unknown_directive_inline.scss:
827
867
  @extending an outer selector from within @flooblehoof is deprecated.
828
868
  You may only @extend selectors within the same directive.
829
869
  This will be an error in Sass 3.3.
@@ -843,7 +883,7 @@ SCSS
843
883
 
844
884
  def test_extend_out_of_nested_directives
845
885
  assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}
846
- DEPRECATION WARNING on line 4 of test_extend_out_of_nested_directives_inline.sass:
886
+ DEPRECATION WARNING on line 4 of test_extend_out_of_nested_directives_inline.scss:
847
887
  @extending an outer selector from within @flooblehoof is deprecated.
848
888
  You may only @extend selectors within the same directive.
849
889
  This will be an error in Sass 3.3.
@@ -946,7 +986,7 @@ SCSS
946
986
 
947
987
  def test_extend_within_and_without_media
948
988
  assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}
949
- DEPRECATION WARNING on line 4 of test_extend_within_and_without_media_inline.sass:
989
+ DEPRECATION WARNING on line 4 of test_extend_within_and_without_media_inline.scss:
950
990
  @extending an outer selector from within @media is deprecated.
951
991
  You may only @extend selectors within the same directive.
952
992
  This will be an error in Sass 3.3.
@@ -969,7 +1009,7 @@ SCSS
969
1009
 
970
1010
  def test_extend_within_and_without_unknown_directive
971
1011
  assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}
972
- DEPRECATION WARNING on line 4 of test_extend_within_and_without_unknown_directive_inline.sass:
1012
+ DEPRECATION WARNING on line 4 of test_extend_within_and_without_unknown_directive_inline.scss:
973
1013
  @extending an outer selector from within @flooblehoof is deprecated.
974
1014
  You may only @extend selectors within the same directive.
975
1015
  This will be an error in Sass 3.3.
@@ -992,7 +1032,7 @@ SCSS
992
1032
 
993
1033
  def test_extend_within_and_without_nested_directives
994
1034
  assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}
995
- DEPRECATION WARNING on line 5 of test_extend_within_and_without_nested_directives_inline.sass:
1035
+ DEPRECATION WARNING on line 5 of test_extend_within_and_without_nested_directives_inline.scss:
996
1036
  @extending an outer selector from within @flooblehoof is deprecated.
997
1037
  You may only @extend selectors within the same directive.
998
1038
  This will be an error in Sass 3.3.
@@ -1071,6 +1111,74 @@ x! .bar {
1071
1111
  CSS
1072
1112
  x! .bar {a: b}
1073
1113
  y! .bap {@extend .bar}
1114
+ SCSS
1115
+ end
1116
+
1117
+ def test_extend_warns_when_extendee_doesnt_exist
1118
+ assert_warning(<<WARN) {assert_equal("", render(<<SCSS))}
1119
+ WARNING on line 1 of test_extend_warns_when_extendee_doesnt_exist_inline.scss: ".foo" failed to @extend ".bar".
1120
+ The selector ".bar" was not found.
1121
+ This will be an error in future releases of Sass.
1122
+ WARN
1123
+ .foo {@extend .bar}
1124
+ SCSS
1125
+ end
1126
+
1127
+ def test_extend_warns_when_extension_fails
1128
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}
1129
+ WARNING on line 2 of test_extend_warns_when_extension_fails_inline.scss: "b.foo" failed to @extend ".bar".
1130
+ No selectors matching ".bar" could be unified with "b.foo".
1131
+ This will be an error in future releases of Sass.
1132
+ WARN
1133
+ a.bar {
1134
+ a: b; }
1135
+ CSS
1136
+ a.bar {a: b}
1137
+ b.foo {@extend .bar}
1138
+ SCSS
1139
+ end
1140
+
1141
+ def test_extend_does_not_warn_when_one_extension_fails_but_others_dont
1142
+ assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}
1143
+ a.bar {
1144
+ a: b; }
1145
+
1146
+ .bar, b.foo {
1147
+ c: d; }
1148
+ CSS
1149
+ a.bar {a: b}
1150
+ .bar {c: d}
1151
+ b.foo {@extend .bar}
1152
+ SCSS
1153
+ end
1154
+
1155
+ def test_extend_does_not_warn_when_one_extension_fails_but_others_dont
1156
+ assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}
1157
+ a.bar {
1158
+ a: b; }
1159
+
1160
+ .bar, b.foo {
1161
+ c: d; }
1162
+ CSS
1163
+ a.bar {a: b}
1164
+ .bar {c: d}
1165
+ b.foo {@extend .bar}
1166
+ SCSS
1167
+ end
1168
+
1169
+ def test_optional_extend_does_not_warn_when_extendee_doesnt_exist
1170
+ assert_no_warning {assert_equal("", render(<<SCSS))}
1171
+ .foo {@extend .bar !optional}
1172
+ SCSS
1173
+ end
1174
+
1175
+ def test_optional_extend_does_not_warn_when_extension_fails
1176
+ assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}
1177
+ a.bar {
1178
+ a: b; }
1179
+ CSS
1180
+ a.bar {a: b}
1181
+ b.foo {@extend .bar !optional}
1074
1182
  SCSS
1075
1183
  end
1076
1184
 
@@ -1184,6 +1292,22 @@ SCSS
1184
1292
 
1185
1293
  private
1186
1294
 
1295
+ def assert_extend_doesnt_match(extender, target, reason, line, syntax = :scss)
1296
+ warn = "\"#{extender}\" failed to @extend \"#{target}\"."
1297
+ reason =
1298
+ if reason == :not_found
1299
+ "The selector \"#{target}\" was not found."
1300
+ else
1301
+ "No selectors matching \"#{target}\" could be unified with \"#{extender}\"."
1302
+ end
1303
+
1304
+ assert_warning(<<WARNING) {yield}
1305
+ WARNING on line #{line} of #{filename_for_test syntax}: #{warn}
1306
+ #{reason}
1307
+ This will be an error in future releases of Sass.
1308
+ WARNING
1309
+ end
1310
+
1187
1311
  def assert_unification(selector, extension, unified)
1188
1312
  # Do some trickery so the first law of extend doesn't get in our way.
1189
1313
  assert_extends(
@@ -1203,7 +1327,8 @@ SCSS
1203
1327
  end
1204
1328
 
1205
1329
  def render(sass, options = {})
1330
+ options = {:syntax => :scss}.merge(options)
1206
1331
  munge_filename options
1207
- Sass::Engine.new(sass, {:syntax => :scss}.merge(options)).render
1332
+ Sass::Engine.new(sass, options).render
1208
1333
  end
1209
1334
  end
@@ -47,6 +47,15 @@ class Test::Unit::TestCase
47
47
  $stderr = the_real_stderr
48
48
  end
49
49
 
50
+ def assert_no_warning
51
+ the_real_stderr, $stderr = $stderr, StringIO.new
52
+ yield
53
+
54
+ assert_equal '', $stderr.string
55
+ ensure
56
+ $stderr = the_real_stderr
57
+ end
58
+
50
59
  def silence_warnings(&block)
51
60
  Sass::Util.silence_warnings(&block)
52
61
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sass
3
3
  version: !ruby/object:Gem::Version
4
- hash: 592302359
4
+ hash: 592302341
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
9
  - 0
10
10
  - alpha
11
- - 261
12
- version: 3.2.0.alpha.261
11
+ - 268
12
+ version: 3.2.0.alpha.268
13
13
  platform: ruby
14
14
  authors:
15
15
  - Nathan Weizenbaum
@@ -19,7 +19,7 @@ autorequire:
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2012-06-29 00:00:00 -04:00
22
+ date: 2012-07-13 00:00:00 -04:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency