-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
simple.rb
119 lines (110 loc) · 4.68 KB
/
simple.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
module Sass
module Selector
# The abstract superclass for simple selectors
# (that is, those that don't compose multiple selectors).
class Simple
# The line of the Sass template on which this selector was declared.
#
# @return [Fixnum]
attr_accessor :line
# 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).
#
# @return [String, nil]
attr_accessor :filename
# Returns a representation of the node
# as an array of strings and potentially {Sass::Script::Node}s
# (if there's interpolation in the selector).
# When the interpolation is resolved and the strings are joined together,
# this will be the string representation of this node.
#
# @return [Array<String, Sass::Script::Node>]
def to_a
Sass::Util.abstract(self)
end
# Returns a string representation of the node.
# This is basically the selector string.
#
# @return [String]
def inspect
to_a.map {|e| e.is_a?(Sass::Script::Node) ? "\#{#{e.to_sass}}" : e}.join
end
# @see \{#inspect}
# @return [String]
def to_s
inspect
end
# Returns a hash code for this selector object.
#
# By default, this is based on the value of \{#to\_a},
# so if that contains information irrelevant to the identity of the selector,
# this should be overridden.
#
# @return [Fixnum]
def hash
@_hash ||= to_a.hash
end
# Checks equality between this and another object.
#
# By default, this is based on the value of \{#to\_a},
# so if that contains information irrelevant to the identity of the selector,
# this should be overridden.
#
# @param other [Object] The object to test equality against
# @return [Boolean] Whether or not this is equal to `other`
def eql?(other)
other.class == self.class && other.hash == self.hash && other.to_a.eql?(to_a)
end
alias_method :==, :eql?
# Unifies this selector with a {SimpleSequence}'s {SimpleSequence#members members array},
# returning another `SimpleSequence` members array
# that matches both this selector and the input selector.
#
# By default, this just appends this selector to the end of the array
# (or returns the original array if this selector already exists in it).
#
# @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
# @return [Array<Simple>, nil] A {SimpleSequence} {SimpleSequence#members members array}
# 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 sels if sels.any? {|sel2| eql?(sel2)}
sels_with_ix = Sass::Util.enum_with_index(sels)
_, i =
if self.is_a?(Pseudo) || self.is_a?(SelectorPseudoClass)
sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) && (sels.last.final? || sels.last.type == :element)}
else
sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) || sel.is_a?(SelectorPseudoClass)}
end
return sels + [self] unless i
return sels[0...i] + [self] + sels[i..-1]
end
protected
# Unifies two namespaces,
# returning a namespace that works for both of them if possible.
#
# @param ns1 [String, nil] The first namespace.
# `nil` means none specified, e.g. `foo`.
# The empty string means no namespace specified, e.g. `|foo`.
# `"*"` means any namespace is allowed, e.g. `*|foo`.
# @param ns2 [String, nil] The second namespace. See `ns1`.
# @return [Array(String or nil, Boolean)]
# The first value is the unified namespace, or `nil` for no namespace.
# The second value is whether or not a namespace that works for both inputs
# could be found at all.
# If the second value is `false`, the first should be ignored.
def unify_namespaces(ns1, ns2)
return nil, false unless ns1 == ns2 || ns1.nil? || ns1 == ['*'] || ns2.nil? || ns2 == ['*']
return ns2, true if ns1 == ['*']
return ns1, true if ns2 == ['*']
return ns1 || ns2, true
end
end
end
end