Class | Sass::Selector::Sequence |
In: |
lib/sass/selector/sequence.rb
|
Parent: | AbstractSequence |
An operator-separated sequence of {SimpleSequence simple selector sequences}.
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>] |
@param seqs_and_ops [Array<SimpleSequence, String>] See \{members}
# File lib/sass/selector/sequence.rb, line 38 38: def initialize(seqs_and_ops) 39: @members = seqs_and_ops 40: end
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}.
# 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]
# 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]
# 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]
# 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
# 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]
# 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
# 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
# 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
# File lib/sass/selector/sequence.rb, line 228 228: def _hash 229: members.reject {|m| m == "\n"}.hash 230: end
# 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
# 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>>]
# 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
# 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.
# 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