Class: Sass::Selector::Sequence

Inherits:
AbstractSequence show all
Defined in:
lib/sass/selector/sequence.rb

Overview

An operator-separated sequence of simple selector sequences.

Instance Attribute Summary collapse

Attributes inherited from AbstractSequence

#filename, #line

Instance Method Summary collapse

Methods inherited from AbstractSequence

#_specificity, #eql?, #hash, #invisible?, #specificity

Constructor Details

#initialize(seqs_and_ops) ⇒ Sequence

Returns a new instance of Sequence.

Parameters:



38
39
40
# File 'lib/sass/selector/sequence.rb', line 38

def initialize(seqs_and_ops)
  @members = seqs_and_ops
end

Instance Attribute Details

#membersArray<SimpleSequence, String|Array<Sass::Tree::Node, String>> (readonly)

The array of simple selector sequences, operators, and newlines. The operators are strings such as "+" and ">" representing the corresponding CSS operators, or interpolated SassScript. Newlines are also newline strings; these aren't semantically relevant, but they do affect formatting.

Returns:



34
35
36
# File 'lib/sass/selector/sequence.rb', line 34

def members
  @members
end

Instance Method Details

#add_sources!(sources)

Add to the Sass::Selector::SimpleSequence#sources sets of the child simple sequences. This destructively modifies this sequence's members array, but not the child simple sequences.

Parameters:



181
182
183
# File 'lib/sass/selector/sequence.rb', line 181

def add_sources!(sources)
  members.map! {|m| m.is_a?(SimpleSequence) ? m.with_more_sources(sources) : m}
end

#contains_parent_ref?Boolean

Returns whether there's a Parent selector anywhere in this sequence.

Returns:

  • (Boolean)


83
84
85
86
87
88
89
90
91
# File 'lib/sass/selector/sequence.rb', line 83

def contains_parent_ref?
  members.any? do |sseq_or_op|
    next false unless sseq_or_op.is_a?(SimpleSequence)
    next true if sseq_or_op.members.first.is_a?(Parent)
    sseq_or_op.members.any? do |sel|
      sel.is_a?(Pseudo) && sel.selector && sel.selector.contains_parent_ref?
    end
  end
end

#do_extend(extends, parent_directives, replace, seen, original) ⇒ Array<Sequence>

Non-destructively extends this selector with the extensions specified in a hash (which should come from Tree::Visitors::Cssize).

The extensions to perform on this selector

Parameters:

Returns:

See Also:



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/sass/selector/sequence.rb', line 113

def do_extend(extends, parent_directives, replace, seen, original)
  extended_not_expanded = members.map do |sseq_or_op|
    next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
    extended = sseq_or_op.do_extend(extends, parent_directives, replace, seen)

    # The First Law of Extend says that the generated selector should have
    # specificity greater than or equal to that of the original selector.
    # In order to ensure that, we record the original selector's
    # (`extended.first`) original specificity.
    extended.first.add_sources!([self]) if original && !invisible?

    extended.map {|seq| seq.members}
  end
  weaves = Sass::Util.paths(extended_not_expanded).map {|path| weave(path)}
  trim(weaves).map {|p| Sequence.new(p)}
end

#filename=(filename) ⇒ String?

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.

Parameters:

  • filename (String, nil)

Returns:

  • (String, nil)


22
23
24
25
# File 'lib/sass/selector/sequence.rb', line 22

def filename=(filename)
  members.each {|m| m.filename = filename if m.is_a?(SimpleSequence)}
  filename
end

#inspectString

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

Returns:

  • (String)


172
173
174
# File 'lib/sass/selector/sequence.rb', line 172

def inspect
  members.map {|m| m.inspect}.join(" ")
end

#line=(line) ⇒ Integer

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

Parameters:

  • line (Integer)

Returns:

  • (Integer)


11
12
13
14
# File 'lib/sass/selector/sequence.rb', line 11

def line=(line)
  members.each {|m| m.line = line if m.is_a?(SimpleSequence)}
  @line = line
end

#resolve_parent_refs(super_cseq, implicit_parent) ⇒ CommaSequence

Resolves the Parent selectors within this selector by replacing them with the given parent selector, handling commas appropriately.

Parameters:

  • super_cseq (CommaSequence)

    The parent selector

  • implicit_parent (Boolean)

    Whether the the parent selector should automatically be prepended to the resolved selector if it contains no parent refs.

Returns:

  • (CommaSequence)

    This selector, with parent references resolved

Raises:



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/sass/selector/sequence.rb', line 52

def resolve_parent_refs(super_cseq, implicit_parent)
  members = @members.dup
  nl = (members.first == "\n" && members.shift)
  contains_parent_ref = contains_parent_ref?
  return CommaSequence.new([self]) if !implicit_parent && !contains_parent_ref

  unless contains_parent_ref
    old_members, members = members, []
    members << nl if nl
    members << SimpleSequence.new([Parent.new], false)
    members += old_members
  end

  CommaSequence.new(Sass::Util.paths(members.map do |sseq_or_op|
    next [sseq_or_op] unless sseq_or_op.is_a?(SimpleSequence)
    sseq_or_op.resolve_parent_refs(super_cseq).members
  end).map do |path|
    path_members = path.map do |seq_or_op|
      next seq_or_op unless seq_or_op.is_a?(Sequence)
      seq_or_op.members
    end
    if path_members.length == 2 && path_members[1][0] == "\n"
      path_members[0].unshift path_members[1].shift
    end
    Sequence.new(path_members.flatten)
  end)
end

#subjectless

Converts the subject operator "!", if it exists, into a ":has()" selector.



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/sass/selector/sequence.rb', line 189

def subjectless
  pre_subject = []
  has = []
  subject = nil
  members.each do |sseq_or_op|
    if subject
      has << sseq_or_op
    elsif sseq_or_op.is_a?(String) || !sseq_or_op.subject?
      pre_subject << sseq_or_op
    else
      subject = sseq_or_op.dup
      subject.members = sseq_or_op.members.dup
      subject.subject = false
      has = []
    end
  end

  return self unless subject

  unless has.empty?
    subject.members << Pseudo.new(:class, 'has', nil, CommaSequence.new([Sequence.new(has)]))
  end
  Sequence.new(pre_subject + [subject])
end

#superselector?(seq) ⇒ Boolean

Returns whether or not this selector matches all elements that the given selector matches (as well as possibly more).

Examples:

(.foo).superselector?(.foo.bar) #=> true
(.foo).superselector?(.bar) #=> false

Parameters:

Returns:

  • (Boolean)


159
160
161
# File 'lib/sass/selector/sequence.rb', line 159

def superselector?(seq)
  _superselector?(members, seq.members)
end

#to_s(opts = {})



164
165
166
# File 'lib/sass/selector/sequence.rb', line 164

def to_s(opts = {})
  @members.map {|m| m.is_a?(String) ? m : m.to_s(opts)}.join(" ").gsub(/ ?\n ?/, "\n")
end

#unify(other) ⇒ CommaSequence?

Unifies this with another selector sequence to produce a selector that matches (a subset of) the intersection of the two inputs.

Parameters:

Returns:

  • (CommaSequence, nil)

    The unified selector, or nil if unification failed.

Raises:

  • (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



141
142
143
144
145
146
147
148
149
# File 'lib/sass/selector/sequence.rb', line 141

def unify(other)
  base = members.last
  other_base = other.members.last
  return unless base.is_a?(SimpleSequence) && other_base.is_a?(SimpleSequence)
  return unless (unified = other_base.unify(base))

  woven = weave([members[0...-1], other.members[0...-1] + [unified]])
  CommaSequence.new(woven.map {|w| Sequence.new(w)})
end