PageRenderTime 57ms CodeModel.GetById 16ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 0ms

/scalate-jruby/src/main/resources/haml-3.0.25/lib/sass/selector/simple_sequence.rb

http://github.com/scalate/scalate
Ruby | 136 lines | 58 code | 15 blank | 63 comment | 7 complexity | abb11c85a88261dc7e69331c1f4446f3 MD5 | raw file
  1module Sass
  2  module Selector
  3    # A unseparated sequence of selectors
  4    # that all apply to a single element.
  5    # For example, `.foo#bar[attr=baz]` is a simple sequence
  6    # of the selectors `.foo`, `#bar`, and `[attr=baz]`.
  7    class SimpleSequence < AbstractSequence
  8      # The array of individual selectors.
  9      #
 10      # @return [Array<Simple>]
 11      attr_reader :members
 12
 13      # Returns the element or universal selector in this sequence,
 14      # if it exists.
 15      #
 16      # @return [Element, Universal, nil]
 17      def base
 18        @base ||= (members.first if members.first.is_a?(Element) || members.first.is_a?(Universal))
 19      end
 20
 21      # Returns the non-base selectors in this sequence.
 22      #
 23      # @return [Set<Simple>]
 24      def rest
 25        @rest ||= Set.new(base ? members[1..-1] : members)
 26      end
 27
 28      # @param selectors [Array<Simple>] See \{#members}
 29      def initialize(selectors)
 30        @members = selectors
 31      end
 32
 33      # Resolves the {Parent} selectors within this selector
 34      # by replacing them with the given parent selector,
 35      # handling commas appropriately.
 36      #
 37      # @param super_seq [Sequence] The parent selector sequence
 38      # @return [Array<SimpleSequence>] This selector, with parent references resolved.
 39      #   This is an array because the parent selector is itself a {Sequence}
 40      # @raise [Sass::SyntaxError] If a parent selector is invalid
 41      def resolve_parent_refs(super_seq)
 42        # Parent selector only appears as the first selector in the sequence
 43        return [self] unless @members.first.is_a?(Parent)
 44
 45        return super_seq.members if @members.size == 1
 46        unless super_seq.members.last.is_a?(SimpleSequence)
 47          raise Sass::SyntaxError.new("Invalid parent selector: " + super_seq.to_a.join)
 48        end
 49
 50        super_seq.members[0...-1] +
 51          [SimpleSequence.new(super_seq.members.last.members + @members[1..-1])]
 52      end
 53
 54      # Non-destrucively extends this selector
 55      # with the extensions specified in a hash
 56      # (which should be populated via {Sass::Tree::Node#cssize}).
 57      #
 58      # @overload def do_extend(extends)
 59      # @param extends [{Selector::Simple => Selector::Sequence}]
 60      #   The extensions to perform on this selector
 61      # @return [Array<Sequence>] A list of selectors generated
 62      #   by extending this selector with `extends`.
 63      # @see CommaSequence#do_extend
 64      def do_extend(extends, seen = Set.new)
 65        extends.get(members.to_set).map do |seq, sels|
 66          # If A {@extend B} and C {...},
 67          # seq is A, sels is B, and self is C
 68
 69          self_without_sel = self.members - sels
 70          next unless unified = seq.members.last.unify(self_without_sel)
 71          [sels, seq.members[0...-1] + [unified]]
 72        end.compact.map do |sels, seq|
 73          seq = Sequence.new(seq)
 74          seen.include?(sels) ? [] : seq.do_extend(extends, seen + [sels])
 75        end.flatten.uniq
 76      end
 77
 78      # Unifies this selector with another {SimpleSequence}'s {SimpleSequence#members members array},
 79      # returning another `SimpleSequence`
 80      # that matches both this selector and the input selector.
 81      #
 82      # @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
 83      # @return [SimpleSequence, nil] A {SimpleSequence} matching both `sels` and this selector,
 84      #   or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
 85      # @raise [Sass::SyntaxError] If this selector cannot be unified.
 86      #   This will only ever occur when a dynamic selector,
 87      #   such as {Parent} or {Interpolation}, is used in unification.
 88      #   Since these selectors should be resolved
 89      #   by the time extension and unification happen,
 90      #   this exception will only ever be raised as a result of programmer error
 91      def unify(sels)
 92        return unless sseq = members.inject(sels) do |sseq, sel|
 93          return unless sseq
 94          sel.unify(sseq)
 95        end
 96        SimpleSequence.new(sseq)
 97      end
 98
 99      # Returns whether or not this selector matches all elements
100      # that the given selector matches (as well as possibly more).
101      #
102      # @example
103      # (.foo).superselector?(.foo.bar) #=> true
104      # (.foo).superselector?(.bar) #=> false
105      #
106      # @param sseq [SimpleSequence]
107      # @return [Boolean]
108      def superselector?(sseq)
109        (base.nil? || base.eql?(sseq.base)) && rest.subset?(sseq.rest)
110      end
111
112      # @see Simple#to_a
113      def to_a
114        @members.map {|sel| sel.to_a}.flatten
115      end
116
117      # Returns a string representation of the sequence.
118      # This is basically the selector string.
119      #
120      # @return [String]
121      def inspect
122        members.map {|m| m.inspect}.join
123      end
124
125      private
126
127      def _hash
128        [base, Haml::Util.set_hash(rest)].hash
129      end
130
131      def _eql?(other)
132        other.base.eql?(self.base) && Haml::Util.set_eql?(other.rest, self.rest)
133      end
134    end
135  end
136end