sass 3.2.0.alpha.247 → 3.2.0.alpha.258

Sign up to get free protection for your applications and to get access to all the features.
data/REVISION CHANGED
@@ -1 +1 @@
1
- 5cc7590756da94e5c6df3da3be9ca8ff946d7279
1
+ 77bf74d8fe5dc1ee1301f5e06676ae8581ddfd73
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0.alpha.247
1
+ 3.2.0.alpha.258
@@ -82,6 +82,7 @@ module Sass
82
82
  nest_seqs root
83
83
  parent_ref_rules root
84
84
  flatten_rules root
85
+ bubble_subject root
85
86
  fold_commas root
86
87
  dump_selectors root
87
88
  root
@@ -212,14 +213,16 @@ module Sass
212
213
  firsts, rest = [sseq.members.first], sseq.members[1..-1]
213
214
  firsts.push rest.shift if firsts.first.is_a?(Sass::Selector::Parent)
214
215
 
215
- if current_rule.nil? || first_sseq(current_rule).members != firsts
216
+ last_simple_subject = rest.empty? && sseq.subject?
217
+ if current_rule.nil? || first_sseq(current_rule).members != firsts ||
218
+ !!first_sseq(current_rule).subject? != !!last_simple_subject
216
219
  current_rule = Tree::RuleNode.new([])
217
- current_rule.parsed_rules = make_sseq(*firsts)
220
+ current_rule.parsed_rules = make_sseq(last_simple_subject, *firsts)
218
221
  end
219
222
 
220
223
  unless rest.empty?
221
224
  rest.unshift Sass::Selector::Parent.new
222
- child.parsed_rules = make_sseq(*rest)
225
+ child.parsed_rules = make_sseq(sseq.subject?, *rest)
223
226
  current_rule << child
224
227
  else
225
228
  current_rule.children += child.children
@@ -287,6 +290,19 @@ module Sass
287
290
  flatten_rules(rule)
288
291
  end
289
292
 
293
+ def bubble_subject(root)
294
+ root.children.each do |child|
295
+ bubble_subject(child) if child.is_a?(Tree::RuleNode) || child.is_a?(Tree::DirectiveNode)
296
+ next unless child.is_a?(Tree::RuleNode)
297
+ next unless child.children.all? do |c|
298
+ next unless c.is_a?(Tree::RuleNode)
299
+ first_simple_sel(c).is_a?(Sass::Selector::Parent) && first_sseq(c).subject?
300
+ end
301
+ first_sseq(child).subject = true
302
+ child.children.each {|c| first_sseq(c).subject = false}
303
+ end
304
+ end
305
+
290
306
  # Transform
291
307
  #
292
308
  # foo
@@ -355,10 +371,11 @@ module Sass
355
371
  # {Sass::Selector::Sequence} which in turn contains only a single
356
372
  # {Sass::Selector::SimpleSequence}.
357
373
  #
374
+ # @param subject [Boolean] Whether this is a subject selector
358
375
  # @param sseqs [Array<Sass::Selector::Sequence, String>]
359
376
  # @return [Sass::Selector::CommaSequence]
360
- def make_sseq(*sseqs)
361
- make_seq(Sass::Selector::SimpleSequence.new(sseqs))
377
+ def make_sseq(subject, *sseqs)
378
+ make_seq(Sass::Selector::SimpleSequence.new(sseqs, subject))
362
379
  end
363
380
 
364
381
  # Return the first {Sass::Selector::Sequence} in a {Sass::Tree::RuleNode}.
@@ -144,6 +144,9 @@ module Sass::Script
144
144
  # \{#join join($list1, $list2, \[$separator\])}
145
145
  # : Joins together two lists into one.
146
146
  #
147
+ # \{#append append($list1, $val, \[$separator\])}
148
+ # : Appends a single value onto the end of a list.
149
+ #
147
150
  # ## Introspection Functions
148
151
  #
149
152
  # \{#type_of type-of($value)}
@@ -582,7 +585,10 @@ module Sass::Script
582
585
  return Sass::Script::String.new("alpha(#{args.map {|a| a.to_s}.join(", ")})")
583
586
  end
584
587
 
585
- opacity(*args)
588
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 1)") if args.size != 1
589
+
590
+ assert_type args.first, :Color
591
+ Sass::Script::Number.new(args.first.alpha)
586
592
  end
587
593
  declare :alpha, [:color]
588
594
 
@@ -595,6 +601,7 @@ module Sass::Script
595
601
  # @see #transparentize
596
602
  # @raise [ArgumentError] If `color` isn't a color
597
603
  def opacity(color)
604
+ return Sass::Script::String.new("opacity(#{color})") if color.is_a?(Sass::Script::Number)
598
605
  assert_type color, :Color
599
606
  Sass::Script::Number.new(color.alpha)
600
607
  end
@@ -685,16 +692,21 @@ module Sass::Script
685
692
  # @example
686
693
  # saturate(hsl(120, 30%, 90%), 20%) => hsl(120, 50%, 90%)
687
694
  # saturate(#855, 20%) => #9e3f3f
688
- # @param color [Color]
689
- # @param amount [Number]
690
- # @return [Color]
691
- # @see #desaturate
692
- # @raise [ArgumentError] If `color` isn't a color,
693
- # or `number` isn't a number between 0% and 100%
694
- def saturate(color, amount)
695
+ # @overload saturate(color, amount)
696
+ # @param color [Color]
697
+ # @param amount [Number]
698
+ # @return [Color]
699
+ # @see #desaturate
700
+ # @raise [ArgumentError] If `color` isn't a color,
701
+ # or `number` isn't a number between 0% and 100%
702
+ def saturate(color, amount = nil)
703
+ # Support the filter effects definition of saturate.
704
+ # https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
705
+ return Sass::Script::String.new("saturate(#{color})") if amount.nil?
695
706
  _adjust(color, amount, :saturation, 0..100, :+, "%")
696
707
  end
697
708
  declare :saturate, [:color, :amount]
709
+ declare :saturate, [:amount]
698
710
 
699
711
  # Makes a color less saturated.
700
712
  # Takes a color and an amount between 0% and 100%,
@@ -995,21 +1007,13 @@ module Sass::Script
995
1007
  declare :mix, [:color_1, :color_2]
996
1008
  declare :mix, [:color_1, :color_2, :weight]
997
1009
 
998
- # @overload grayscale(color)
999
- # Converts a color to grayscale.
1000
- # This is identical to `desaturate(color, 100%)`.
1001
- #
1002
- # @param color [Color]
1003
- # @return [Color]
1004
- # @raise [ArgumentError] if `color` isn't a color
1005
- # @see #desaturate
1006
- # @overload grayscale(number)
1007
- # Returns an unquoted string `grayscale(number)`, as though the function
1008
- # were not defined. This is for the `grayscale` function used in
1009
- # `-webkit-filter`.
1010
+ # Converts a color to grayscale.
1011
+ # This is identical to `desaturate(color, 100%)`.
1010
1012
  #
1011
- # @param number [Number]
1012
- # @return [Sass::Script::String]
1013
+ # @param color [Color]
1014
+ # @return [Color]
1015
+ # @raise [ArgumentError] if `color` isn't a color
1016
+ # @see #desaturate
1013
1017
  def grayscale(color)
1014
1018
  return Sass::Script::String.new("grayscale(#{color})") if color.is_a?(Sass::Script::Number)
1015
1019
  desaturate color, Number.new(100)
@@ -1035,6 +1039,8 @@ module Sass::Script
1035
1039
  # @return [Color]
1036
1040
  # @raise [ArgumentError] if `color` isn't a color
1037
1041
  def invert(color)
1042
+ return Sass::Script::String.new("invert(#{color})") if color.is_a?(Sass::Script::Number)
1043
+
1038
1044
  assert_type color, :Color
1039
1045
  color.with(
1040
1046
  :red => (255 - color.red),
@@ -1328,14 +1334,14 @@ module Sass::Script
1328
1334
  # append(10px 20px, 30px) => 10px 20px 30px
1329
1335
  # append((blue, red), green) => blue, red, green
1330
1336
  # append(10px 20px, 30px 40px) => 10px 20px (30px 40px)
1331
- # join(10px, 20px, comma) => 10px, 20px
1332
- # join((blue, red), green, space) => blue red green
1333
- # @overload join(list, val, separator: auto)
1334
- # @param list1 [Literal] The first list to join
1335
- # @param list2 [Literal] The second list to join
1337
+ # append(10px, 20px, comma) => 10px, 20px
1338
+ # append((blue, red), green, space) => blue red green
1339
+ # @overload append(list, val, separator: auto)
1340
+ # @param list [Literal] The list to add the value to
1341
+ # @param val [Literal] The value to add to the end of the list
1336
1342
  # @param separator [String] How the list separator (comma or space) should be determined.
1337
1343
  # If this is `comma` or `space`, that is always the separator;
1338
- # if this is `auto` (the default), the separator is determined as explained above.
1344
+ # if this is `auto` (the default), the separator is the same as that used by the list.
1339
1345
  def append(list, val, separator = Sass::Script::String.new("auto"))
1340
1346
  assert_type separator, :String
1341
1347
  unless %w[auto space comma].include?(separator.value)
@@ -82,7 +82,7 @@ module Sass::Script
82
82
 
83
83
  literal2 = @operand2.perform(environment)
84
84
 
85
- if literal1.is_a?(Null) || literal2.is_a?(Null)
85
+ if (literal1.is_a?(Null) || literal2.is_a?(Null)) && @operator != :eq && @operator != :neq
86
86
  raise Sass::SyntaxError.new("Invalid null operation: \"#{literal1.inspect} #{@operator} #{literal2.inspect}\".")
87
87
  end
88
88
 
@@ -541,7 +541,7 @@ module Sass
541
541
  end
542
542
 
543
543
  # This is a nasty hack, and the only place in the parser
544
- # that requires backtracking.
544
+ # that requires a large amount of backtracking.
545
545
  # The reason is that we can't figure out if certain strings
546
546
  # are declarations or rulesets with fixed finite lookahead.
547
547
  # For example, "foo:bar baz baz baz..." could be either a property
@@ -631,19 +631,31 @@ module Sass
631
631
  end
632
632
 
633
633
  def combinator
634
- tok(PLUS) || tok(GREATER) || tok(TILDE)
634
+ tok(PLUS) || tok(GREATER) || tok(TILDE) || reference_combinator
635
+ end
636
+
637
+ def reference_combinator
638
+ return unless tok(/\//)
639
+ res = ['/']
640
+ ns, name = expr!(:qualified_name)
641
+ res << ns << '|' if ns
642
+ res << name << tok!(/\//)
643
+ res = res.flatten
644
+ res = res.join '' if res.all? {|e| e.is_a?(String)}
645
+ res
635
646
  end
636
647
 
637
648
  def simple_selector_sequence
638
- # This allows for stuff like http://www.w3.org/TR/css3-animations/#keyframes-
649
+ # Returning expr by default allows for stuff like
650
+ # http://www.w3.org/TR/css3-animations/#keyframes-
639
651
  return expr(!:allow_var) unless e = element_name || id_selector ||
640
- class_selector || placeholder_selector || attrib || negation ||
641
- pseudo || parent_selector || interpolation_selector
652
+ class_selector || placeholder_selector || attrib || pseudo ||
653
+ parent_selector || interpolation_selector
642
654
  res = [e]
643
655
 
644
656
  # The tok(/\*/) allows the "E*" hack
645
657
  while v = id_selector || class_selector || placeholder_selector || attrib ||
646
- negation || pseudo || interpolation_selector ||
658
+ pseudo || interpolation_selector ||
647
659
  (tok(/\*/) && Selector::Universal.new(nil))
648
660
  res << v
649
661
  end
@@ -664,7 +676,7 @@ module Sass
664
676
  end
665
677
  end
666
678
 
667
- Selector::SimpleSequence.new(res)
679
+ Selector::SimpleSequence.new(res, tok(/!/))
668
680
  end
669
681
 
670
682
  def parent_selector
@@ -691,12 +703,8 @@ module Sass
691
703
  end
692
704
 
693
705
  def element_name
694
- return unless name = interp_ident || tok(/\*/) || (tok?(/\|/) && "")
695
- if tok(/\|/)
696
- @expected = "element name or *"
697
- ns = name
698
- name = interp_ident || tok!(/\*/)
699
- end
706
+ ns, name = qualified_name(:allow_star_name)
707
+ return unless ns || name
700
708
 
701
709
  if name == '*'
702
710
  Selector::Universal.new(merge(ns))
@@ -705,6 +713,15 @@ module Sass
705
713
  end
706
714
  end
707
715
 
716
+ def qualified_name(allow_star_name=false)
717
+ return unless name = interp_ident || tok(/\*/) || (tok?(/\|/) && "")
718
+ return nil, name unless tok(/\|/)
719
+
720
+ return name, expr!(:interp_ident) unless allow_star_name
721
+ @expected = "identifier or *"
722
+ return name, interp_ident || tok!(/\*/)
723
+ end
724
+
708
725
  def interpolation_selector
709
726
  return unless script = interpolation
710
727
  Selector::Interpolation.new(script)
@@ -727,9 +744,10 @@ module Sass
727
744
  val = interp_ident || expr!(:interp_string)
728
745
  ss
729
746
  end
747
+ flags = interp_ident || interp_string
730
748
  tok!(/\]/)
731
749
 
732
- Selector::Attribute.new(merge(name), merge(ns), op, merge(val))
750
+ Selector::Attribute.new(merge(name), merge(ns), op, merge(val), merge(flags))
733
751
  end
734
752
 
735
753
  def attrib_name!
@@ -756,32 +774,53 @@ module Sass
756
774
  name = expr!(:interp_ident)
757
775
  if tok(/\(/)
758
776
  ss
759
- arg = expr!(:pseudo_expr)
777
+ arg = expr!(:pseudo_arg)
778
+ while tok(/,/)
779
+ arg << ',' << str{ss}
780
+ arg.concat expr!(:pseudo_arg)
781
+ end
760
782
  tok!(/\)/)
761
783
  end
762
784
  Selector::Pseudo.new(s == ':' ? :class : :element, merge(name), merge(arg))
763
785
  end
764
786
 
787
+ def pseudo_arg
788
+ # In the CSS spec, every pseudo-class/element either takes a pseudo
789
+ # expression or a selector comma sequence as an argument. However, we
790
+ # don't want to have to know which takes which, so we handle both at
791
+ # once.
792
+ #
793
+ # However, there are some ambiguities between the two. For instance, "n"
794
+ # could start a pseudo expression like "n+1", or it could start a
795
+ # selector like "n|m". In order to handle this, we must regrettably
796
+ # backtrack.
797
+ expr, sel = nil
798
+ pseudo_err = catch_error do
799
+ expr = pseudo_expr
800
+ next if tok?(/[,)]/)
801
+ expr = nil
802
+ expected '")"'
803
+ end
804
+
805
+ return expr if expr
806
+ sel_err = catch_error {sel = selector}
807
+ return sel if sel
808
+ rethrow pseudo_err if pseudo_err
809
+ rethrow sel_err if sel_err
810
+ return
811
+ end
812
+
765
813
  def pseudo_expr
766
- return unless e = tok(PLUS) || tok(/-/) || tok(NUMBER) ||
814
+ return unless e = tok(PLUS) || tok(/[-*]/) || tok(NUMBER) ||
767
815
  interp_string || tok(IDENT) || interpolation
768
816
  res = [e, str{ss}]
769
- while e = tok(PLUS) || tok(/-/) || tok(NUMBER) ||
817
+ while e = tok(PLUS) || tok(/[-*]/) || tok(NUMBER) ||
770
818
  interp_string || tok(IDENT) || interpolation
771
819
  res << e << str{ss}
772
820
  end
773
821
  res
774
822
  end
775
823
 
776
- def negation
777
- return unless name = tok(NOT) || tok(ANY)
778
- ss
779
- @expected = "selector"
780
- sel = selector_comma_sequence
781
- tok!(/\)/)
782
- Selector::SelectorPseudoClass.new(name[1...-1], sel)
783
- end
784
-
785
824
  def declaration
786
825
  # This allows the "*prop: val", ":prop: val", and ".prop: val" hacks
787
826
  if s = tok(/[:\*\.]|\#(?!\{)/)
@@ -980,12 +1019,12 @@ MESSAGE
980
1019
  EXPR_NAMES = {
981
1020
  :media_query => "media query (e.g. print, screen, print and screen)",
982
1021
  :media_expr => "media expression (e.g. (min-device-width: 800px))",
983
- :pseudo_expr => "expression (e.g. fr, 2n+1)",
1022
+ :pseudo_arg => "expression (e.g. fr, 2n+1)",
984
1023
  :interp_ident => "identifier",
985
1024
  :interp_name => "identifier",
1025
+ :qualified_name => "identifier",
986
1026
  :expr => "expression (e.g. 1px, bold)",
987
1027
  :_selector => "selector",
988
- :selector_comma_sequence => "selector",
989
1028
  :simple_selector_sequence => "selector",
990
1029
  :import_arg => "file to import (string or url())",
991
1030
  :moz_document_function => "matching function (e.g. url-prefix(), domain())",
@@ -1041,7 +1080,7 @@ MESSAGE
1041
1080
  pos = @scanner.pos
1042
1081
  line = @line
1043
1082
  expected = @expected
1044
- if catch(:_sass_parser_error, &block)
1083
+ if catch(:_sass_parser_error) {yield; false}
1045
1084
  @scanner.pos = pos
1046
1085
  @line = line
1047
1086
  @expected = expected
@@ -309,15 +309,22 @@ module Sass
309
309
  # @return [Array<String, Sass::Script::Node>]
310
310
  attr_reader :value
311
311
 
312
+ # Flags for the attribute selector (e.g. `i`).
313
+ #
314
+ # @return [Array<String, Sass::Script::Node>]
315
+ attr_reader :flags
316
+
312
317
  # @param name [Array<String, Sass::Script::Node>] The attribute name
313
318
  # @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
314
319
  # @param operator [String] The matching operator, e.g. `"="` or `"^="`
315
320
  # @param value [Array<String, Sass::Script::Node>] See \{#value}
316
- def initialize(name, namespace, operator, value)
321
+ # @param value [Array<String, Sass::Script::Node>] See \{#flags}
322
+ def initialize(name, namespace, operator, value, flags)
317
323
  @name = name
318
324
  @namespace = namespace
319
325
  @operator = operator
320
326
  @value = value
327
+ @flags = flags
321
328
  end
322
329
 
323
330
  # @see Selector#to_a
@@ -326,6 +333,7 @@ module Sass
326
333
  res.concat(@namespace) << "|" if @namespace
327
334
  res.concat @name
328
335
  (res << @operator).concat @value if @value
336
+ (res << " ").concat @flags if @flags
329
337
  res << "]"
330
338
  end
331
339
 
@@ -24,17 +24,16 @@ module Sass
24
24
  filename
25
25
  end
26
26
 
27
- # The array of {SimpleSequence simple selector sequences}, operators, and newlines.
28
- # The operators are strings such as `"+"` and `">"`
29
- # representing the corresponding CSS operators.
30
- # Newlines are also newline strings;
31
- # these aren't semantically relevant,
32
- # but they do affect formatting.
27
+ # The array of {SimpleSequence simple selector sequences}, operators, and
28
+ # newlines. The operators are strings such as `"+"` and `">"` representing
29
+ # the corresponding CSS operators, or interpolated SassScript. Newlines
30
+ # are also newline strings; these aren't semantically relevant, but they
31
+ # do affect formatting.
33
32
  #
34
- # @return [Array<SimpleSequence, String>]
33
+ # @return [Array<SimpleSequence, String|Array<Sass::Tree::Node, String>>]
35
34
  attr_reader :members
36
35
 
37
- # @param seqs_and_ops [Array<SimpleSequence, String>] See \{#members}
36
+ # @param seqs_and_ops [Array<SimpleSequence, String|Array<Sass::Tree::Node, String>>] See \{#members}
38
37
  def initialize(seqs_and_ops)
39
38
  @members = seqs_and_ops
40
39
  end
@@ -54,7 +53,7 @@ module Sass
54
53
  end
55
54
  members = []
56
55
  members << nl if nl
57
- members << SimpleSequence.new([Parent.new])
56
+ members << SimpleSequence.new([Parent.new], false)
58
57
  members += @members
59
58
  end
60
59
 
@@ -198,7 +197,7 @@ module Sass
198
197
  diff += fin.map {|sel| sel.is_a?(Array) ? sel : [sel]}
199
198
  diff.reject! {|c| c.empty?}
200
199
 
201
- Sass::Util.paths(diff).map {|p| p.flatten}
200
+ Sass::Util.paths(diff).map {|p| p.flatten}.reject {|p| path_has_two_subjects?(p)}
202
201
  end
203
202
 
204
203
  # Extracts initial selector combinators (`"+"`, `">"`, `"~"`, and `"\n"`)
@@ -272,7 +271,7 @@ module Sass
272
271
  elsif sel2.superselector?(sel1)
273
272
  res.unshift sel1, '~'
274
273
  else
275
- merged = sel1.unify(sel2.members)
274
+ merged = sel1.unify(sel2.members, sel2.subject?)
276
275
  res.unshift [
277
276
  [sel1, '~', sel2, '~'],
278
277
  [sel2, '~', sel1, '~'],
@@ -289,7 +288,7 @@ module Sass
289
288
  if tilde_sel.superselector?(plus_sel)
290
289
  res.unshift plus_sel, '+'
291
290
  else
292
- merged = plus_sel.unify(tilde_sel.members)
291
+ merged = plus_sel.unify(tilde_sel.members, tilde_sel.subject?)
293
292
  res.unshift [
294
293
  [tilde_sel, '~', plus_sel, '+'],
295
294
  ([merged, '+'] if merged)
@@ -302,7 +301,7 @@ module Sass
302
301
  res.unshift sel1, op1
303
302
  seq2.push sel2, op2
304
303
  elsif op1 == op2
305
- return unless merged = sel1.unify(sel2.members)
304
+ return unless merged = sel1.unify(sel2.members, sel2.subject?)
306
305
  res.unshift merged, op1
307
306
  else
308
307
  # Unknown selector combinators can't be unified
@@ -422,7 +421,7 @@ module Sass
422
421
  # @param seq2 [Array<SimpleSequence or String>]
423
422
  # @return [Boolean]
424
423
  def parent_superselector?(seq1, seq2)
425
- base = Sass::Selector::SimpleSequence.new([Sass::Selector::Placeholder.new('<temp>')])
424
+ base = Sass::Selector::SimpleSequence.new([Sass::Selector::Placeholder.new('<temp>')], false)
426
425
  _superselector?(seq1 + [base], seq2 + [base])
427
426
  end
428
427
 
@@ -467,6 +466,17 @@ module Sass
467
466
 
468
467
  private
469
468
 
469
+ def path_has_two_subjects?(path)
470
+ subject = false
471
+ path.each do |sseq_or_op|
472
+ next unless sseq_or_op.is_a?(SimpleSequence)
473
+ next unless sseq_or_op.subject?
474
+ return true if subject
475
+ subject = true
476
+ end
477
+ false
478
+ end
479
+
470
480
  def _sources(seq)
471
481
  s = Set.new
472
482
  seq.map {|sseq_or_op| s.merge sseq_or_op.sources if sseq_or_op.is_a?(SimpleSequence)}
@@ -26,6 +26,9 @@ module Sass
26
26
  # @return {Set<Sequence>}
27
27
  attr_accessor :sources
28
28
 
29
+ # @see \{#subject?}
30
+ attr_writer :subject
31
+
29
32
  # Returns the element or universal selector in this sequence,
30
33
  # if it exists.
31
34
  #
@@ -41,10 +44,21 @@ module Sass
41
44
  @rest ||= Set.new(base ? members[1..-1] : members)
42
45
  end
43
46
 
47
+ # Whether or not this compound selector is the subject of the parent
48
+ # selector; that is, whether it is prepended with `$` and represents the
49
+ # actual element that will be selected.
50
+ #
51
+ # @return [Boolean]
52
+ def subject?
53
+ @subject
54
+ end
55
+
44
56
  # @param selectors [Array<Simple>] See \{#members}
57
+ # @param subject [Boolean] See \{#subject?}
45
58
  # @param sources [Set<Sequence>]
46
- def initialize(selectors, sources = Set.new)
59
+ def initialize(selectors, subject, sources = Set.new)
47
60
  @members = selectors
61
+ @subject = subject
48
62
  @sources = sources
49
63
  end
50
64
 
@@ -66,7 +80,7 @@ module Sass
66
80
  end
67
81
 
68
82
  super_seq.members[0...-1] +
69
- [SimpleSequence.new(super_seq.members.last.members + @members[1..-1])]
83
+ [SimpleSequence.new(super_seq.members.last.members + @members[1..-1], subject?)]
70
84
  end
71
85
 
72
86
  # Non-destrucively extends this selector with the extensions specified in a hash
@@ -88,7 +102,7 @@ module Sass
88
102
  # seq is A, sels is B, and self is C
89
103
 
90
104
  self_without_sel = self.members - sels
91
- next unless unified = seq.members.last.unify(self_without_sel)
105
+ next unless unified = seq.members.last.unify(self_without_sel, subject?)
92
106
  next if group.map {|e, _| check_directives_match!(e, parent_directives)}.none?
93
107
  new_seq = Sequence.new(seq.members[0...-1] + [unified])
94
108
  new_seq.add_sources!(sources + [seq])
@@ -103,6 +117,7 @@ module Sass
103
117
  # that matches both this selector and the input selector.
104
118
  #
105
119
  # @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
120
+ # @param subject [Boolean] Whether the {SimpleSequence} being merged is a subject.
106
121
  # @return [SimpleSequence, nil] A {SimpleSequence} matching both `sels` and this selector,
107
122
  # or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
108
123
  # @raise [Sass::SyntaxError] If this selector cannot be unified.
@@ -111,12 +126,12 @@ module Sass
111
126
  # Since these selectors should be resolved
112
127
  # by the time extension and unification happen,
113
128
  # this exception will only ever be raised as a result of programmer error
114
- def unify(sels)
129
+ def unify(sels, other_subject)
115
130
  return unless sseq = members.inject(sels) do |sseq, sel|
116
131
  return unless sseq
117
132
  sel.unify(sseq)
118
133
  end
119
- SimpleSequence.new(sseq)
134
+ SimpleSequence.new(sseq, other_subject || subject?)
120
135
  end
121
136
 
122
137
  # Returns whether or not this selector matches all elements
@@ -133,7 +148,9 @@ module Sass
133
148
 
134
149
  # @see Simple#to_a
135
150
  def to_a
136
- @members.map {|sel| sel.to_a}.flatten
151
+ res = @members.map {|sel| sel.to_a}.flatten
152
+ res << '!' if subject?
153
+ res
137
154
  end
138
155
 
139
156
  # Returns a string representation of the sequence.
@@ -178,7 +195,8 @@ WARNING
178
195
  end
179
196
 
180
197
  def _eql?(other)
181
- other.base.eql?(self.base) && Sass::Util.set_eql?(other.rest, self.rest)
198
+ other.base.eql?(self.base) && Sass::Util.set_eql?(other.rest, self.rest) &&
199
+ other.subject? == self.subject?
182
200
  end
183
201
  end
184
202
  end
@@ -214,7 +214,8 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
214
214
  rule.resolved_rules = Sass::Selector::CommaSequence.new(
215
215
  [Sass::Selector::Sequence.new(
216
216
  [Sass::Selector::SimpleSequence.new(
217
- [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)])
217
+ [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)],
218
+ false)
218
219
  ])
219
220
  ])
220
221
  prop = Sass::Tree::PropNode.new([""], Sass::Script::String.new(''), :new)
@@ -462,9 +462,9 @@ module Sass
462
462
  # Like `Dir.glob`, but works with backslash-separated paths on Windows.
463
463
  #
464
464
  # @param path [String]
465
- def glob(path)
465
+ def glob(path, &block)
466
466
  path = path.gsub('\\', '/') if windows?
467
- Dir.glob(path)
467
+ Dir.glob(path, &block)
468
468
  end
469
469
 
470
470
  ## Cross-Ruby-Version Compatibility
@@ -74,10 +74,17 @@ SCSS
74
74
  assert_renders <<SASS, <<SCSS
75
75
  foo \#{$bar + "baz"}.bip
76
76
  baz: bang
77
+
78
+ foo /\#{$bar + "baz"}/ .bip
79
+ baz: bang
77
80
  SASS
78
81
  foo \#{$bar + "baz"}.bip {
79
82
  baz: bang;
80
83
  }
84
+
85
+ foo /\#{$bar + "baz"}/ .bip {
86
+ baz: bang;
87
+ }
81
88
  SCSS
82
89
  end
83
90
 
@@ -1403,6 +1410,28 @@ SASS
1403
1410
  SCSS
1404
1411
  end
1405
1412
 
1413
+ def test_reference_selector
1414
+ assert_renders(<<SASS, <<SCSS)
1415
+ foo /bar|baz/ bang
1416
+ a: b
1417
+ SASS
1418
+ foo /bar|baz/ bang {
1419
+ a: b;
1420
+ }
1421
+ SCSS
1422
+ end
1423
+
1424
+ def test_subject
1425
+ assert_renders(<<SASS, <<SCSS)
1426
+ foo bar! baz
1427
+ a: b
1428
+ SASS
1429
+ foo bar! baz {
1430
+ a: b;
1431
+ }
1432
+ SCSS
1433
+ end
1434
+
1406
1435
  def test_placeholder_interoplation_conversion
1407
1436
  assert_renders(<<SASS, <<SCSS)
1408
1437
  $foo: foo
@@ -1523,7 +1552,6 @@ foo bar {
1523
1552
  SCSS
1524
1553
  end
1525
1554
 
1526
-
1527
1555
  ## Regression Tests
1528
1556
 
1529
1557
  def test_empty_lists
@@ -237,6 +237,32 @@ SASS
237
237
  CSS
238
238
  end
239
239
 
240
+ def test_subject
241
+ assert_equal(<<SASS, css2sass(<<CSS))
242
+ .foo
243
+ .bar!
244
+ .baz
245
+ a: b
246
+ .bip
247
+ c: d
248
+ .bar .bonk
249
+ e: f
250
+
251
+ .flip!
252
+ &.bar
253
+ a: b
254
+ &.baz
255
+ c: d
256
+ SASS
257
+ .foo .bar! .baz {a: b;}
258
+ .foo .bar! .bip {c: d;}
259
+ .foo .bar .bonk {e: f;}
260
+
261
+ .flip.bar! {a: b;}
262
+ .flip.baz! {c: d;}
263
+ CSS
264
+ end
265
+
240
266
  # Regressions
241
267
 
242
268
  def test_nesting_within_media
@@ -2716,7 +2716,7 @@ SASS
2716
2716
  end
2717
2717
 
2718
2718
  def test_comment_like_selector
2719
- assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "": expected selector, was "/ foo"') {render(<<SASS)}
2719
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "/": expected identifier, was " foo"') {render(<<SASS)}
2720
2720
  / foo
2721
2721
  a: b
2722
2722
  SASS
@@ -414,6 +414,12 @@ SCSS
414
414
  assert_extends 'a ~ b c .c1', 'b c .c2 {@extend .c1}', 'a ~ b c .c1, a ~ b c .c2'
415
415
  end
416
416
 
417
+ def test_nested_extender_doesnt_find_common_selectors_around_reference_selector
418
+ assert_extends 'a /for/ b c .c1', 'a c .c2 {@extend .c1}', 'a /for/ b c .c1, a /for/ b a c .c2, a a /for/ b c .c2'
419
+ assert_extends 'a /for/ b c .c1', 'a b .c2 {@extend .c1}', 'a /for/ b c .c1, a a /for/ b c .c2'
420
+ assert_extends 'a /for/ b c .c1', 'b c .c2 {@extend .c1}', 'a /for/ b c .c1, a /for/ b c .c2'
421
+ end
422
+
417
423
  def test_nested_extender_with_early_child_selectors_doesnt_subseq_them
418
424
  assert_extends('.bip > .bap .foo', '.grip > .bap .bar {@extend .foo}',
419
425
  '.bip > .bap .foo, .bip > .bap .grip > .bap .bar, .grip > .bap .bip > .bap .bar')
@@ -443,7 +449,9 @@ CSS
443
449
  > .baz {@extend .bar}
444
450
  }
445
451
  SCSS
452
+ end
446
453
 
454
+ def test_nested_extender_with_early_child_selectors_doesnt_subseq_them
447
455
  assert_equal <<CSS, render(<<SCSS)
448
456
  .foo .bar, .foo .bip > .baz {
449
457
  a: b; }
@@ -1008,6 +1016,64 @@ CSS
1008
1016
  SCSS
1009
1017
  end
1010
1018
 
1019
+ def test_extend_with_subject_transfers_subject_to_extender
1020
+ assert_equal(<<CSS, render(<<SCSS))
1021
+ foo bar! baz, foo .bip .bap! baz, .bip foo .bap! baz {
1022
+ a: b; }
1023
+ CSS
1024
+ foo bar! baz {a: b}
1025
+ .bip .bap {@extend bar}
1026
+ SCSS
1027
+
1028
+ assert_equal(<<CSS, render(<<SCSS))
1029
+ foo.x bar.y! baz.z, foo.x .bip bar.bap! baz.z, .bip foo.x bar.bap! baz.z {
1030
+ a: b; }
1031
+ CSS
1032
+ foo.x bar.y! baz.z {a: b}
1033
+ .bip .bap {@extend .y}
1034
+ SCSS
1035
+ end
1036
+
1037
+ def test_extend_with_subject_retains_subject_on_target
1038
+ assert_equal(<<CSS, render(<<SCSS))
1039
+ .foo! .bar, .foo! .bip .bap, .bip .foo! .bap {
1040
+ a: b; }
1041
+ CSS
1042
+ .foo! .bar {a: b}
1043
+ .bip .bap {@extend .bar}
1044
+ SCSS
1045
+ end
1046
+
1047
+ def test_extend_with_subject_transfers_subject_to_target
1048
+ assert_equal(<<CSS, render(<<SCSS))
1049
+ a.foo .bar, .bip a.bap! .bar {
1050
+ a: b; }
1051
+ CSS
1052
+ a.foo .bar {a: b}
1053
+ .bip .bap! {@extend .foo}
1054
+ SCSS
1055
+ end
1056
+
1057
+ def test_extend_with_subject_retains_subject_on_extender
1058
+ assert_equal(<<CSS, render(<<SCSS))
1059
+ .foo .bar, .foo .bip! .bap, .bip! .foo .bap {
1060
+ a: b; }
1061
+ CSS
1062
+ .foo .bar {a: b}
1063
+ .bip! .bap {@extend .bar}
1064
+ SCSS
1065
+ end
1066
+
1067
+ def test_extend_with_subject_fails_with_conflicting_subject
1068
+ assert_equal(<<CSS, render(<<SCSS))
1069
+ x! .bar {
1070
+ a: b; }
1071
+ CSS
1072
+ x! .bar {a: b}
1073
+ y! .bap {@extend .bar}
1074
+ SCSS
1075
+ end
1076
+
1011
1077
  # Regression Tests
1012
1078
 
1013
1079
  def test_newline_near_combinator
@@ -336,6 +336,18 @@ class SassFunctionTest < Test::Unit::TestCase
336
336
  assert_error_message("12 is not a color for `alpha'", "alpha(12)")
337
337
  end
338
338
 
339
+ def test_opacity
340
+ assert_equal("1", evaluate("opacity(#123456)"))
341
+ assert_equal("0.34", evaluate("opacity(rgba(0, 1, 2, 0.34))"))
342
+ assert_equal("0", evaluate("opacity(hsla(0, 1, 2, 0))"))
343
+ assert_equal("0", evaluate("opacity($color: hsla(0, 1, 2, 0))"))
344
+ assert_equal("opacity(20%)", evaluate("opacity(20%)"))
345
+ end
346
+
347
+ def test_opacity_exception
348
+ assert_error_message("\"foo\" is not a color for `opacity'", "opacity(foo)")
349
+ end
350
+
339
351
  def test_opacify
340
352
  assert_equal("rgba(0, 0, 0, 0.75)", evaluate("opacify(rgba(0, 0, 0, 0.5), 0.25)"))
341
353
  assert_equal("rgba(0, 0, 0, 0.3)", evaluate("opacify(rgba(0, 0, 0, 0.2), 0.1)"))
@@ -435,6 +447,7 @@ class SassFunctionTest < Test::Unit::TestCase
435
447
  assert_equal("#88aa88", evaluate("saturate(#8a8, 0%)"))
436
448
  assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate(rgba(136, 85, 85, 0.5), 20%)"))
437
449
  assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate($color: rgba(136, 85, 85, 0.5), $amount: 20%)"))
450
+ assert_equal("saturate(50%)", evaluate("saturate(50%)"))
438
451
  end
439
452
 
440
453
  def test_saturate_tests_bounds
@@ -828,6 +841,7 @@ class SassFunctionTest < Test::Unit::TestCase
828
841
  def test_invert
829
842
  assert_equal("#112233", evaluate("invert(#edc)"))
830
843
  assert_equal("rgba(245, 235, 225, 0.5)", evaluate("invert(rgba(10, 20, 30, 0.5))"))
844
+ assert_equal("invert(20%)", evaluate("invert(20%)"))
831
845
  end
832
846
 
833
847
  def test_invert_tests_types
@@ -385,6 +385,16 @@ SASS
385
385
  assert_equal "false", resolve('(1 (2 3)) == (1 2 3)')
386
386
  assert_equal "false", resolve('((1, 2) (3, 4)) == (1, 2 3, 4)')
387
387
  assert_equal "false", resolve('(1 2 3) == (1, 2, 3)')
388
+
389
+ assert_equal "true", resolve('null == null')
390
+ assert_equal "false", resolve('"null" == null')
391
+ assert_equal "false", resolve('0 == null')
392
+ assert_equal "false", resolve('() == null')
393
+
394
+ assert_equal "false", resolve('null != null')
395
+ assert_equal "true", resolve('"null" != null')
396
+ assert_equal "true", resolve('0 != null')
397
+ assert_equal "true", resolve('() != null')
388
398
  end
389
399
 
390
400
  def test_operation_precedence
@@ -650,91 +650,140 @@ SCSS
650
650
 
651
651
  ## Selectors
652
652
 
653
- # Taken from http://www.w3.org/TR/css3-selectors/#selectors
653
+ # Taken from http://dev.w3.org/csswg/selectors4/#overview
654
654
  def test_summarized_selectors
655
655
  assert_selector_parses('*')
656
656
  assert_selector_parses('E')
657
+ assert_selector_parses('E:not(s)')
658
+ assert_selector_parses('E:not(s1, s2)')
659
+ assert_selector_parses('E:matches(s1, s2)')
660
+ assert_selector_parses('E.warning')
661
+ assert_selector_parses('E#myid')
657
662
  assert_selector_parses('E[foo]')
658
663
  assert_selector_parses('E[foo="bar"]')
664
+ assert_selector_parses('E[foo="bar" i]')
659
665
  assert_selector_parses('E[foo~="bar"]')
660
666
  assert_selector_parses('E[foo^="bar"]')
661
667
  assert_selector_parses('E[foo$="bar"]')
662
668
  assert_selector_parses('E[foo*="bar"]')
663
669
  assert_selector_parses('E[foo|="en"]')
664
- assert_selector_parses('E:root')
665
- assert_selector_parses('E:nth-child(n)')
666
- assert_selector_parses('E:nth-last-child(n)')
667
- assert_selector_parses('E:nth-of-type(n)')
668
- assert_selector_parses('E:nth-last-of-type(n)')
669
- assert_selector_parses('E:first-child')
670
- assert_selector_parses('E:last-child')
671
- assert_selector_parses('E:first-of-type')
672
- assert_selector_parses('E:last-of-type')
673
- assert_selector_parses('E:only-child')
674
- assert_selector_parses('E:only-of-type')
675
- assert_selector_parses('E:empty')
670
+ assert_selector_parses('E:dir(ltr)')
671
+ assert_selector_parses('E:lang(fr)')
672
+ assert_selector_parses('E:lang(zh, *-hant)')
673
+ assert_selector_parses('E:any-link')
676
674
  assert_selector_parses('E:link')
677
675
  assert_selector_parses('E:visited')
676
+ assert_selector_parses('E:local-link')
677
+ assert_selector_parses('E:local-link(0)')
678
+ assert_selector_parses('E:target')
679
+ assert_selector_parses('E:scope')
680
+ assert_selector_parses('E:current')
681
+ assert_selector_parses('E:current(s)')
682
+ assert_selector_parses('E:past')
683
+ assert_selector_parses('E:future')
678
684
  assert_selector_parses('E:active')
679
685
  assert_selector_parses('E:hover')
680
686
  assert_selector_parses('E:focus')
681
- assert_selector_parses('E:target')
682
- assert_selector_parses('E:lang(fr)')
683
687
  assert_selector_parses('E:enabled')
684
688
  assert_selector_parses('E:disabled')
685
689
  assert_selector_parses('E:checked')
686
- assert_selector_parses('E::first-line')
687
- assert_selector_parses('E::first-letter')
688
- assert_selector_parses('E::before')
689
- assert_selector_parses('E::after')
690
- assert_selector_parses('E.warning')
691
- assert_selector_parses('E#myid')
692
- assert_selector_parses('E:not(s)')
690
+ assert_selector_parses('E:indeterminate')
691
+ assert_selector_parses('E:default')
692
+ assert_selector_parses('E:in-range')
693
+ assert_selector_parses('E:out-of-range')
694
+ assert_selector_parses('E:required')
695
+ assert_selector_parses('E:optional')
696
+ assert_selector_parses('E:read-only')
697
+ assert_selector_parses('E:read-write')
698
+ assert_selector_parses('E:root')
699
+ assert_selector_parses('E:empty')
700
+ assert_selector_parses('E:first-child')
701
+ assert_selector_parses('E:nth-child(n)')
702
+ assert_selector_parses('E:last-child')
703
+ assert_selector_parses('E:nth-last-child(n)')
704
+ assert_selector_parses('E:only-child')
705
+ assert_selector_parses('E:first-of-type')
706
+ assert_selector_parses('E:nth-of-type(n)')
707
+ assert_selector_parses('E:last-of-type')
708
+ assert_selector_parses('E:nth-last-of-type(n)')
709
+ assert_selector_parses('E:only-of-type')
710
+ assert_selector_parses('E:nth-match(n of selector)')
711
+ assert_selector_parses('E:nth-last-match(n of selector)')
712
+ assert_selector_parses('E:column(selector)')
713
+ assert_selector_parses('E:nth-column(n)')
714
+ assert_selector_parses('E:nth-last-column(n)')
693
715
  assert_selector_parses('E F')
694
716
  assert_selector_parses('E > F')
695
717
  assert_selector_parses('E + F')
696
718
  assert_selector_parses('E ~ F')
719
+ assert_selector_parses('E /foo/ F')
720
+ assert_selector_parses('E! > F')
721
+
722
+ assert_selector_parses('E /ns|foo/ F')
723
+ assert_selector_parses('E /*|foo/ F')
697
724
  end
698
725
 
699
- # Taken from http://www.w3.org/TR/css3-selectors/#selectors,
700
- # but without the element names
701
- def test_lonely_selectors
726
+ # Taken from http://dev.w3.org/csswg/selectors4/#overview, but without element
727
+ # names.
728
+ def test_summarized_selectors
729
+ assert_selector_parses(':not(s)')
730
+ assert_selector_parses(':not(s1, s2)')
731
+ assert_selector_parses(':matches(s1, s2)')
732
+ assert_selector_parses('.warning')
733
+ assert_selector_parses('#myid')
702
734
  assert_selector_parses('[foo]')
703
735
  assert_selector_parses('[foo="bar"]')
736
+ assert_selector_parses('[foo="bar" i]')
704
737
  assert_selector_parses('[foo~="bar"]')
705
738
  assert_selector_parses('[foo^="bar"]')
706
739
  assert_selector_parses('[foo$="bar"]')
707
740
  assert_selector_parses('[foo*="bar"]')
708
741
  assert_selector_parses('[foo|="en"]')
709
- assert_selector_parses(':root')
710
- assert_selector_parses(':nth-child(n)')
711
- assert_selector_parses(':nth-last-child(n)')
712
- assert_selector_parses(':nth-of-type(n)')
713
- assert_selector_parses(':nth-last-of-type(n)')
714
- assert_selector_parses(':first-child')
715
- assert_selector_parses(':last-child')
716
- assert_selector_parses(':first-of-type')
717
- assert_selector_parses(':last-of-type')
718
- assert_selector_parses(':only-child')
719
- assert_selector_parses(':only-of-type')
720
- assert_selector_parses(':empty')
742
+ assert_selector_parses(':dir(ltr)')
743
+ assert_selector_parses(':lang(fr)')
744
+ assert_selector_parses(':lang(zh, *-hant)')
745
+ assert_selector_parses(':any-link')
721
746
  assert_selector_parses(':link')
722
747
  assert_selector_parses(':visited')
748
+ assert_selector_parses(':local-link')
749
+ assert_selector_parses(':local-link(0)')
750
+ assert_selector_parses(':target')
751
+ assert_selector_parses(':scope')
752
+ assert_selector_parses(':current')
753
+ assert_selector_parses(':current(s)')
754
+ assert_selector_parses(':past')
755
+ assert_selector_parses(':future')
723
756
  assert_selector_parses(':active')
724
757
  assert_selector_parses(':hover')
725
758
  assert_selector_parses(':focus')
726
- assert_selector_parses(':target')
727
- assert_selector_parses(':lang(fr)')
728
759
  assert_selector_parses(':enabled')
729
760
  assert_selector_parses(':disabled')
730
761
  assert_selector_parses(':checked')
731
- assert_selector_parses('::first-line')
732
- assert_selector_parses('::first-letter')
733
- assert_selector_parses('::before')
734
- assert_selector_parses('::after')
735
- assert_selector_parses('.warning')
736
- assert_selector_parses('#myid')
737
- assert_selector_parses(':not(s)')
762
+ assert_selector_parses(':indeterminate')
763
+ assert_selector_parses(':default')
764
+ assert_selector_parses(':in-range')
765
+ assert_selector_parses(':out-of-range')
766
+ assert_selector_parses(':required')
767
+ assert_selector_parses(':optional')
768
+ assert_selector_parses(':read-only')
769
+ assert_selector_parses(':read-write')
770
+ assert_selector_parses(':root')
771
+ assert_selector_parses(':empty')
772
+ assert_selector_parses(':first-child')
773
+ assert_selector_parses(':nth-child(n)')
774
+ assert_selector_parses(':last-child')
775
+ assert_selector_parses(':nth-last-child(n)')
776
+ assert_selector_parses(':only-child')
777
+ assert_selector_parses(':first-of-type')
778
+ assert_selector_parses(':nth-of-type(n)')
779
+ assert_selector_parses(':last-of-type')
780
+ assert_selector_parses(':nth-last-of-type(n)')
781
+ assert_selector_parses(':only-of-type')
782
+ assert_selector_parses(':nth-match(n of selector)')
783
+ assert_selector_parses(':nth-last-match(n of selector)')
784
+ assert_selector_parses(':column(selector)')
785
+ assert_selector_parses(':nth-column(n)')
786
+ assert_selector_parses(':nth-last-column(n)')
738
787
  end
739
788
 
740
789
  def test_attribute_selectors_with_identifiers
@@ -771,36 +820,41 @@ CSS
771
820
  SCSS
772
821
  end
773
822
 
774
- def test_negation_selectors
775
- assert_selector_parses(':not(foo|bar)')
776
- assert_selector_parses(':not(*|bar)')
823
+ def test_selectors_containing_selectors
824
+ assert_selector_can_contain_selectors(':not(<sel>)')
825
+ assert_selector_can_contain_selectors(':current(<sel>)')
826
+ assert_selector_can_contain_selectors(':nth-match(n of <sel>)')
827
+ assert_selector_can_contain_selectors(':nth-last-match(n of <sel>)')
828
+ assert_selector_can_contain_selectors(':column(<sel>)')
829
+ assert_selector_can_contain_selectors(':-moz-any(<sel>)')
830
+ end
831
+
832
+ def assert_selector_can_contain_selectors(sel)
833
+ try = lambda {|subsel| assert_selector_parses(sel.gsub('<sel>', subsel))}
834
+
835
+ try['foo|bar']
836
+ try['*|bar']
777
837
 
778
- assert_selector_parses(':not(foo|*)')
779
- assert_selector_parses(':not(*|*)')
838
+ try['foo|*']
839
+ try['*|*']
780
840
 
781
- assert_selector_parses(':not(#blah)')
782
- assert_selector_parses(':not(.blah)')
841
+ try['#blah']
842
+ try['.blah']
783
843
 
784
- assert_selector_parses(':not([foo])')
785
- assert_selector_parses(':not([foo^="bar"])')
786
- assert_selector_parses(':not([baz|foo~="bar"])')
844
+ try['[foo]']
845
+ try['[foo^="bar"]']
846
+ try['[baz|foo~="bar"]']
787
847
 
788
- assert_selector_parses(':not(:hover)')
789
- assert_selector_parses(':not(:nth-child(2n + 3))')
848
+ try[':hover']
849
+ try[':nth-child(2n + 3)']
790
850
 
791
- # Not technically allowed, but what the heck
792
- assert_selector_parses(':not(:not(#foo))')
793
- assert_selector_parses(':not(a#foo.bar)')
794
- assert_selector_parses(':not(#foo .bar > baz)')
795
- assert_selector_parses(':not(h1, h2, h3)')
796
- end
851
+ try['h1, h2, h3']
852
+ try['#foo, bar, [baz]']
797
853
 
798
- def test_any_selector
799
- assert_selector_parses(':-moz-any(h1, h2, h3)')
800
- assert_selector_parses(':-moz-any(.foo)')
801
- assert_selector_parses(':-moz-any(foo bar, .baz > .bang)')
802
- assert_selector_parses(':-webkit-any(foo bar, .baz > .bang)')
803
- assert_selector_parses(':any(foo bar, .baz > .bang)')
854
+ # Not technically allowed for most selectors, but what the heck
855
+ try[':not(#foo)']
856
+ try['a#foo.bar']
857
+ try['#foo .bar > baz']
804
858
  end
805
859
 
806
860
  def test_namespaced_selectors
@@ -517,6 +517,22 @@ foo {
517
517
  SCSS
518
518
  end
519
519
 
520
+ def test_parent_selector_with_subject
521
+ assert_equal <<CSS, render(<<SCSS)
522
+ bar foo.baz! .bip {
523
+ a: b; }
524
+
525
+ bar foo bar.baz! .bip {
526
+ c: d; }
527
+ CSS
528
+ foo {
529
+ bar &.baz! .bip {a: b}}
530
+
531
+ foo bar {
532
+ bar &.baz! .bip {c: d}}
533
+ SCSS
534
+ end
535
+
520
536
  ## Namespace Properties
521
537
 
522
538
  def test_namespace_properties
@@ -871,6 +887,29 @@ div { -foo-\#{$a}-\#{$b}-foo: foo }
871
887
  SCSS
872
888
  end
873
889
 
890
+ def test_selector_interpolation_in_reference_combinator
891
+ assert_equal <<CSS, render(<<SCSS)
892
+ .foo /a/ .bar /b|c/ .baz {
893
+ a: b; }
894
+ CSS
895
+ $a: a;
896
+ $b: b;
897
+ $c: c;
898
+ .foo /\#{$a}/ .bar /\#{$b}|\#{$c}/ .baz {a: b}
899
+ SCSS
900
+ end
901
+
902
+ def test_parent_selector_with_parent_and_subject
903
+ assert_equal <<CSS, render(<<SCSS)
904
+ bar foo.baz! .bip {
905
+ c: d; }
906
+ CSS
907
+ $subject: "!";
908
+ foo {
909
+ bar &.baz\#{$subject} .bip {c: d}}
910
+ SCSS
911
+ end
912
+
874
913
  def test_basic_prop_name_interpolation
875
914
  assert_equal <<CSS, render(<<SCSS)
876
915
  foo {
@@ -1243,6 +1282,15 @@ SCSS
1243
1282
 
1244
1283
  # Regression
1245
1284
 
1285
+ def test_reference_combinator_with_parent_ref
1286
+ assert_equal <<CSS, render(<<SCSS)
1287
+ a /foo/ b {
1288
+ c: d; }
1289
+ CSS
1290
+ a {& /foo/ b {c: d}}
1291
+ SCSS
1292
+ end
1293
+
1246
1294
  def test_prop_name_interpolation_after_hyphen
1247
1295
  assert_equal <<CSS, render(<<SCSS)
1248
1296
  a {
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: 592302835
4
+ hash: 592302361
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
9
  - 0
10
10
  - alpha
11
- - 247
12
- version: 3.2.0.alpha.247
11
+ - 258
12
+ version: 3.2.0.alpha.258
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-15 00:00:00 -04:00
22
+ date: 2012-06-29 00:00:00 -04:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
@@ -154,7 +154,6 @@ files:
154
154
  - lib/sass/tree/content_node.rb
155
155
  - lib/sass/tree/css_import_node.rb
156
156
  - lib/sass/tree/variable_node.rb
157
- - lib/sass/tree/warn_node.rb
158
157
  - lib/sass/tree/visitors/base.rb
159
158
  - lib/sass/tree/visitors/check_nesting.rb
160
159
  - lib/sass/tree/visitors/convert.rb
@@ -164,6 +163,7 @@ files:
164
163
  - lib/sass/tree/visitors/perform.rb
165
164
  - lib/sass/tree/visitors/set_options.rb
166
165
  - lib/sass/tree/visitors/to_css.rb
166
+ - lib/sass/tree/warn_node.rb
167
167
  - lib/sass/tree/while_node.rb
168
168
  - lib/sass/tree/supports_node.rb
169
169
  - lib/sass/tree/trace_node.rb