/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
- module Sass
- module Selector
- # A unseparated sequence of selectors
- # that all apply to a single element.
- # For example, `.foo#bar[attr=baz]` is a simple sequence
- # of the selectors `.foo`, `#bar`, and `[attr=baz]`.
- class SimpleSequence < AbstractSequence
- # The array of individual selectors.
- #
- # @return [Array<Simple>]
- attr_reader :members
- # Returns the element or universal selector in this sequence,
- # if it exists.
- #
- # @return [Element, Universal, nil]
- def base
- @base ||= (members.first if members.first.is_a?(Element) || members.first.is_a?(Universal))
- end
- # Returns the non-base selectors in this sequence.
- #
- # @return [Set<Simple>]
- def rest
- @rest ||= Set.new(base ? members[1..-1] : members)
- end
- # @param selectors [Array<Simple>] See \{#members}
- def initialize(selectors)
- @members = selectors
- end
- # Resolves the {Parent} selectors within this selector
- # by replacing them with the given parent selector,
- # handling commas appropriately.
- #
- # @param super_seq [Sequence] The parent selector sequence
- # @return [Array<SimpleSequence>] This selector, with parent references resolved.
- # This is an array because the parent selector is itself a {Sequence}
- # @raise [Sass::SyntaxError] If a parent selector is invalid
- def resolve_parent_refs(super_seq)
- # Parent selector only appears as the first selector in the sequence
- return [self] unless @members.first.is_a?(Parent)
- return super_seq.members if @members.size == 1
- unless super_seq.members.last.is_a?(SimpleSequence)
- raise Sass::SyntaxError.new("Invalid parent selector: " + super_seq.to_a.join)
- end
- super_seq.members[0...-1] +
- [SimpleSequence.new(super_seq.members.last.members + @members[1..-1])]
- end
- # Non-destrucively extends this selector
- # with the extensions specified in a hash
- # (which should be populated via {Sass::Tree::Node#cssize}).
- #
- # @overload def do_extend(extends)
- # @param extends [{Selector::Simple => Selector::Sequence}]
- # The extensions to perform on this selector
- # @return [Array<Sequence>] A list of selectors generated
- # by extending this selector with `extends`.
- # @see CommaSequence#do_extend
- def do_extend(extends, seen = Set.new)
- extends.get(members.to_set).map do |seq, sels|
- # If A {@extend B} and C {...},
- # seq is A, sels is B, and self is C
- self_without_sel = self.members - sels
- next unless unified = seq.members.last.unify(self_without_sel)
- [sels, seq.members[0...-1] + [unified]]
- end.compact.map do |sels, seq|
- seq = Sequence.new(seq)
- seen.include?(sels) ? [] : seq.do_extend(extends, seen + [sels])
- end.flatten.uniq
- end
- # Unifies this selector with another {SimpleSequence}'s {SimpleSequence#members members array},
- # returning another `SimpleSequence`
- # that matches both this selector and the input selector.
- #
- # @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
- # @return [SimpleSequence, nil] A {SimpleSequence} matching both `sels` and this selector,
- # or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
- # @raise [Sass::SyntaxError] If this selector cannot be unified.
- # This will only ever occur when a dynamic selector,
- # such as {Parent} or {Interpolation}, is used in unification.
- # Since these selectors should be resolved
- # by the time extension and unification happen,
- # this exception will only ever be raised as a result of programmer error
- def unify(sels)
- return unless sseq = members.inject(sels) do |sseq, sel|
- return unless sseq
- sel.unify(sseq)
- end
- SimpleSequence.new(sseq)
- end
- # Returns whether or not this selector matches all elements
- # that the given selector matches (as well as possibly more).
- #
- # @example
- # (.foo).superselector?(.foo.bar) #=> true
- # (.foo).superselector?(.bar) #=> false
- #
- # @param sseq [SimpleSequence]
- # @return [Boolean]
- def superselector?(sseq)
- (base.nil? || base.eql?(sseq.base)) && rest.subset?(sseq.rest)
- end
- # @see Simple#to_a
- def to_a
- @members.map {|sel| sel.to_a}.flatten
- end
- # Returns a string representation of the sequence.
- # This is basically the selector string.
- #
- # @return [String]
- def inspect
- members.map {|m| m.inspect}.join
- end
- private
- def _hash
- [base, Haml::Util.set_hash(rest)].hash
- end
- def _eql?(other)
- other.base.eql?(self.base) && Haml::Util.set_eql?(other.rest, self.rest)
- end
- end
- end
- end