Class Sass::Selector::Sequence
In: lib/sass/selector/sequence.rb
Parent: AbstractSequence
Haml::Util Engine Color SyntaxError UnitConversionError StandardError AbstractSequence CommaSequence Sequence SimpleSequence Simple Parent Universal Class SelectorPseudoClass Id Pseudo Attribute Interpolation Element Node Operation Literal UnaryOperation StringInterpolation Funcall Interpolation Variable Lexer CssLexer Number Bool String Parser Parser CssParser EvaluationContext StaticParser SassParser CssParser Node DebugNode IfNode CommentNode ForNode PropNode MixinNode DirectiveNode ExtendNode VariableNode WarnNode RootNode WhileNode RuleNode MixinDefNode Enumerable ImportNode Merb::BootLoader MerbBootLoader Repl CSS Environment Rack StalenessChecker lib/sass/repl.rb lib/sass/css.rb lib/sass/environment.rb lib/sass/error.rb lib/sass/engine.rb lib/sass/selector/simple_sequence.rb lib/sass/selector/abstract_sequence.rb lib/sass/selector/sequence.rb lib/sass/selector/comma_sequence.rb lib/sass/selector/simple.rb lib/sass/selector.rb Selector lib/sass/script/css_parser.rb lib/sass/script/lexer.rb lib/sass/script/color.rb lib/sass/script/string.rb lib/sass/script/unary_operation.rb lib/sass/script/variable.rb lib/sass/script/funcall.rb lib/sass/script/string_interpolation.rb lib/sass/script/operation.rb lib/sass/script/bool.rb lib/sass/script/parser.rb lib/sass/script/literal.rb lib/sass/script/node.rb lib/sass/script/interpolation.rb lib/sass/script/css_lexer.rb lib/sass/script/number.rb lib/sass/script/functions.rb Functions Script lib/sass/scss/sass_parser.rb lib/sass/scss/static_parser.rb lib/sass/scss/parser.rb lib/sass/scss/css_parser.rb ScriptLexer ScriptParser RX SCSS Files Callbacks lib/sass/tree/while_node.rb lib/sass/tree/if_node.rb lib/sass/tree/mixin_def_node.rb lib/sass/tree/debug_node.rb lib/sass/tree/root_node.rb lib/sass/tree/for_node.rb lib/sass/tree/import_node.rb lib/sass/tree/prop_node.rb lib/sass/tree/node.rb lib/sass/tree/comment_node.rb lib/sass/tree/extend_node.rb lib/sass/tree/mixin_node.rb lib/sass/tree/warn_node.rb lib/sass/tree/directive_node.rb lib/sass/tree/rule_node.rb lib/sass/tree/variable_node.rb Tree lib/sass/plugin/rack.rb lib/sass/plugin/staleness_checker.rb lib/sass/plugin/merb.rb Plugin Sass dot/m_85_0.png

An operator-separated sequence of {SimpleSequence simple selector sequences}.

Methods

Attributes

members  [R]  The array of {SimpleSequence simple selector sequences}, operators, and newlines. The operators are strings such as `"+"` and `">"` representing the corresponding CSS operators. Newlines are also newline strings; these aren‘t semantically relevant, but they do affect formatting.

@return [Array<SimpleSequence, String>]

Public Class methods

@param seqs_and_ops [Array<SimpleSequence, String>] See \{members}

[Source]

    # File lib/sass/selector/sequence.rb, line 38
38:       def initialize(seqs_and_ops)
39:         @members = seqs_and_ops
40:       end

Public Instance methods

Non-destructively 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 [Haml::Util::SubsetMap{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`.
  These correspond to a {CommaSequence}'s {CommaSequence#members members array}.

@see CommaSequence#do_extend

[Source]

    # File lib/sass/selector/sequence.rb, line 79
79:       def do_extend(extends, seen = Set.new)
80:         paths = Haml::Util.paths(members.map do |sseq_or_op|
81:             next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
82:             extended = sseq_or_op.do_extend(extends, seen)
83:             choices = extended.map {|seq| seq.members}
84:             choices.unshift([sseq_or_op]) unless extended.any? {|seq| seq.superselector?(sseq_or_op)}
85:             choices
86:           end)
87:         Haml::Util.flatten(paths.map {|path| weave(path)}, 1).map {|p| Sequence.new(p)}
88:       end

Sets the name of the file in which this selector was declared, or `nil` if it was not declared in a file (e.g. on stdin). This also sets the filename for all child selectors.

@param filename [String, nil] @return [String, nil]

[Source]

    # File lib/sass/selector/sequence.rb, line 22
22:       def filename=(filename)
23:         members.each {|m| m.filename = filename if m.is_a?(SimpleSequence)}
24:         filename
25:       end

Returns a string representation of the sequence. This is basically the selector string.

@return [String]

[Source]

     # File lib/sass/selector/sequence.rb, line 117
117:       def inspect
118:         members.map {|m| m.inspect}.join(" ")
119:       end

Sets the line of the Sass template on which this selector was declared. This also sets the line for all child selectors.

@param line [Fixnum] @return [Fixnum]

[Source]

    # File lib/sass/selector/sequence.rb, line 11
11:       def line=(line)
12:         members.each {|m| m.line = line if m.is_a?(SimpleSequence)}
13:         line
14:       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 [Sequence] This selector, with parent references resolved @raise [Sass::SyntaxError] If a parent selector is invalid

[Source]

    # File lib/sass/selector/sequence.rb, line 49
49:       def resolve_parent_refs(super_seq)
50:         members = @members
51:         members.slice!(0) if nl = (members.first == "\n")
52:         unless members.any? do |seq_or_op|
53:             seq_or_op.is_a?(SimpleSequence) && seq_or_op.members.first.is_a?(Parent)
54:           end
55:           members = []
56:           members << "\n" if nl
57:           members << SimpleSequence.new([Parent.new])
58:           members += @members
59:         end
60: 
61:         Sequence.new(
62:           members.map do |seq_or_op|
63:             next seq_or_op unless seq_or_op.is_a?(SimpleSequence)
64:             seq_or_op.resolve_parent_refs(super_seq)
65:           end.flatten)
66:       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 (.bar .foo).superselector?(.foo) #=> false

@param sseq [SimpleSequence] @return [Boolean]

[Source]

     # File lib/sass/selector/sequence.rb, line 100
100:       def superselector?(sseq)
101:         return false unless members.size == 1
102:         members.last.superselector?(sseq)
103:       end

@see Simple#to_a

[Source]

     # File lib/sass/selector/sequence.rb, line 106
106:       def to_a
107:         ary = @members.map {|seq_or_op| seq_or_op.is_a?(SimpleSequence) ? seq_or_op.to_a : seq_or_op}
108:         ary = Haml::Util.intersperse(ary, " ")
109:         ary = Haml::Util.substitute(ary, [" ", "\n", " "], ["\n"])
110:         ary.flatten.compact
111:       end

Private Instance methods

[Source]

     # File lib/sass/selector/sequence.rb, line 232
232:       def _eql?(other)
233:         other.members.reject {|m| m == "\n"}.eql?(self.members.reject {|m| m == "\n"})
234:       end

[Source]

     # File lib/sass/selector/sequence.rb, line 228
228:       def _hash
229:         members.reject {|m| m == "\n"}.hash
230:       end

[Source]

     # File lib/sass/selector/sequence.rb, line 185
185:       def chunks(seq1, seq2)
186:         chunk1 = []
187:         chunk1 << seq1.shift until yield seq1
188:         chunk2 = []
189:         chunk2 << seq2.shift until yield seq2
190:         return [] if chunk1.empty? && chunk2.empty?
191:         return [chunk2] if chunk1.empty?
192:         return [chunk1] if chunk2.empty?
193:         [chunk1 + chunk2, chunk2 + chunk1]
194:       end

[Source]

     # File lib/sass/selector/sequence.rb, line 196
196:       def group_selectors(seq)
197:         newseq = []
198:         tail = seq.dup
199:         until tail.empty?
200:           head = []
201:           begin
202:             head << tail.shift
203:           end while !tail.empty? && head.last.is_a?(String) || tail.first.is_a?(String)
204:           newseq << head
205:         end
206:         return newseq
207:       end

This interweaves two lists of selectors, returning all possible orderings of them (including using unification) that maintain the relative ordering of the input arrays.

For example, given `.foo .bar` and `.baz .bang`, this would return `.foo .bar .baz .bang`, `.foo .bar.baz .bang`, `.foo .baz .bar .bang`, `.foo .baz .bar.bang`, `.foo .baz .bang .bar`, and so on until `.baz .bang .foo .bar`.

@overload def subweave(seq1, seq2) @param seq1 [Array<SimpleSequence or String>] @param seq2 [Array<SimpleSequence or String>] @return [Array<Array<SimpleSequence or String>>]

[Source]

     # File lib/sass/selector/sequence.rb, line 160
160:       def subweave(seq1, seq2, cache = {})
161:         return [seq2] if seq1.empty?
162:         return [seq1] if seq2.empty?
163: 
164:         seq1 = group_selectors(seq1)
165:         seq2 = group_selectors(seq2)
166:         lcs = Haml::Util.lcs(seq2, seq1) do |s1, s2|
167:           next s1 if s1 == s2
168:           next unless s1.first.is_a?(SimpleSequence) && s2.first.is_a?(SimpleSequence)
169:           next s2 if subweave_superselector?(s1, s2)
170:           next s1 if subweave_superselector?(s2, s1)
171:         end
172: 
173:         diff = []
174:         until lcs.empty?
175:           diff << chunks(seq1, seq2) {|s| subweave_superselector?(s.first, lcs.first)} << [lcs.shift]
176:           seq1.shift
177:           seq2.shift
178:         end
179:         diff << chunks(seq1, seq2) {|s| s.empty?}
180:         diff.reject! {|c| c.empty?}
181: 
182:         Haml::Util.paths(diff).map {|p| p.flatten}
183:       end

[Source]

     # File lib/sass/selector/sequence.rb, line 209
209:       def subweave_superselector?(sseq1, sseq2)
210:         if sseq1.size > 1
211:           # More complex selectors are never superselectors of less complex ones
212:           return unless sseq2.size > 1
213:           # .foo ~ .bar is a superselector of .foo + .bar
214:           return unless sseq1[1] == "~" ? sseq2[1] != ">" : sseq2[1] == sseq1[1]
215:           return unless sseq1.first.superselector?(sseq2.first)
216:           return true if sseq1.size == 2
217:           return false if sseq2.size == 2
218:           return subweave_superselector?(sseq1[2..-1], sseq2[2..-1])
219:         elsif sseq2.size > 1
220:           return true if sseq2[1] == ">" && sseq1.first.superselector?(sseq2.first)
221:           return false if sseq2.size == 2
222:           return subweave_superselector?(sseq1, sseq2[2..-1])
223:         else
224:           sseq1.first.superselector?(sseq2.first)
225:         end
226:       end

Conceptually, this expands "parenthesized selectors". That is, if we have `.A .B {@extend .C}` and `.D .C {…}`, this conceptually expands into `.D .C, .D (.A .B)`, and this function translates `.D (.A .B)` into `.D .A .B, .A.D .B, .D .A .B`.

@param path [Array<Array<SimpleSequence or String>>] A list of parenthesized selector groups. @return [Array<Array<SimpleSequence or String>>] A list of fully-expanded selectors.

[Source]

     # File lib/sass/selector/sequence.rb, line 130
130:       def weave(path)
131:         befores = [[]]
132:         afters = path.dup
133: 
134:         until afters.empty?
135:           current = afters.shift.dup
136:           last_current = [current.pop]
137:           while !current.empty? && last_current.first.is_a?(String) || current.last.is_a?(String)
138:             last_current.unshift(current.pop)
139:           end
140:           befores = Haml::Util.flatten(befores.map do |before|
141:               subweave(before, current).map {|seqs| seqs + last_current}
142:             end, 1)
143:           return befores if afters.empty?
144:         end
145:       end

[Validate]