haml 3.0.0.beta.3 → 3.0.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of haml might be problematic. Click here for more details.
- data/.yardopts +2 -0
- data/REMEMBER +4 -11
- data/Rakefile +24 -2
- data/VERSION +1 -1
- data/lib/haml.rb +5 -2
- data/lib/haml/exec.rb +11 -4
- data/lib/haml/filters.rb +3 -0
- data/lib/haml/helpers.rb +2 -10
- data/lib/haml/helpers/action_view_extensions.rb +4 -2
- data/lib/haml/helpers/action_view_mods.rb +6 -4
- data/lib/haml/html.rb +0 -1
- data/lib/haml/precompiler.rb +37 -30
- data/lib/haml/railtie.rb +6 -2
- data/lib/haml/root.rb +4 -0
- data/lib/haml/template.rb +2 -0
- data/lib/haml/util.rb +74 -0
- data/lib/haml/util/subset_map.rb +101 -0
- data/lib/sass.rb +1 -0
- data/lib/sass/engine.rb +36 -31
- data/lib/sass/files.rb +1 -1
- data/lib/sass/plugin.rb +21 -0
- data/lib/sass/plugin/staleness_checker.rb +9 -9
- data/lib/sass/script.rb +1 -2
- data/lib/sass/script/color.rb +4 -3
- data/lib/sass/script/css_lexer.rb +11 -1
- data/lib/sass/script/css_parser.rb +4 -1
- data/lib/sass/script/funcall.rb +9 -0
- data/lib/sass/script/interpolation.rb +21 -0
- data/lib/sass/script/lexer.rb +30 -13
- data/lib/sass/script/node.rb +1 -1
- data/lib/sass/script/number.rb +4 -5
- data/lib/sass/script/parser.rb +13 -14
- data/lib/sass/script/string.rb +8 -2
- data/lib/sass/script/string_interpolation.rb +27 -4
- data/lib/sass/scss.rb +3 -0
- data/lib/sass/scss/css_parser.rb +5 -3
- data/lib/sass/scss/parser.rb +146 -64
- data/lib/sass/scss/rx.rb +9 -1
- data/lib/sass/scss/sass_parser.rb +11 -0
- data/lib/sass/scss/script_lexer.rb +2 -0
- data/lib/sass/scss/static_parser.rb +48 -0
- data/lib/sass/selector.rb +353 -0
- data/lib/sass/selector/abstract_sequence.rb +40 -0
- data/lib/sass/selector/comma_sequence.rb +80 -0
- data/lib/sass/selector/sequence.rb +194 -0
- data/lib/sass/selector/simple.rb +107 -0
- data/lib/sass/selector/simple_sequence.rb +161 -0
- data/lib/sass/tree/comment_node.rb +1 -0
- data/lib/sass/tree/debug_node.rb +1 -0
- data/lib/sass/tree/directive_node.rb +1 -0
- data/lib/sass/tree/extend_node.rb +60 -0
- data/lib/sass/tree/for_node.rb +1 -0
- data/lib/sass/tree/if_node.rb +2 -0
- data/lib/sass/tree/import_node.rb +2 -0
- data/lib/sass/tree/mixin_def_node.rb +1 -0
- data/lib/sass/tree/mixin_node.rb +21 -5
- data/lib/sass/tree/node.rb +59 -12
- data/lib/sass/tree/prop_node.rb +20 -21
- data/lib/sass/tree/root_node.rb +8 -17
- data/lib/sass/tree/rule_node.rb +49 -100
- data/lib/sass/tree/variable_node.rb +1 -0
- data/lib/sass/tree/warn_node.rb +1 -0
- data/lib/sass/tree/while_node.rb +1 -0
- data/test/haml/engine_test.rb +185 -3
- data/test/haml/helper_test.rb +25 -2
- data/test/haml/template_test.rb +2 -2
- data/test/haml/templates/helpers.haml +13 -0
- data/test/haml/util/subset_map_test.rb +91 -0
- data/test/haml/util_test.rb +25 -0
- data/test/sass/conversion_test.rb +23 -3
- data/test/sass/engine_test.rb +50 -7
- data/test/sass/extend_test.rb +1045 -0
- data/test/sass/results/complex.css +0 -1
- data/test/sass/results/script.css +1 -1
- data/test/sass/script_conversion_test.rb +16 -0
- data/test/sass/script_test.rb +37 -4
- data/test/sass/scss/css_test.rb +17 -3
- data/test/sass/scss/rx_test.rb +1 -1
- data/test/sass/scss/scss_test.rb +30 -0
- data/test/sass/templates/complex.sass +0 -2
- data/test/test_helper.rb +5 -0
- metadata +18 -4
data/lib/sass/scss/rx.rb
CHANGED
@@ -65,7 +65,8 @@ module Sass
|
|
65
65
|
NAME = /#{NMCHAR}+/
|
66
66
|
NUM = /[0-9]+|[0-9]*.[0-9]+/
|
67
67
|
STRING = /#{STRING1}|#{STRING2}/
|
68
|
-
|
68
|
+
URLCHAR = /[#%&*-~]|#{NONASCII}|#{ESCAPE}/
|
69
|
+
URL = /(#{URLCHAR}*)/
|
69
70
|
W = /[ \t\r\n\f]*/
|
70
71
|
|
71
72
|
# This is more liberal than the spec's definition,
|
@@ -108,6 +109,13 @@ module Sass
|
|
108
109
|
# Custom
|
109
110
|
HEXCOLOR = /\#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?/
|
110
111
|
INTERP_START = /#\{/
|
112
|
+
|
113
|
+
STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|\\#{NL}|#{ESCAPE})*)\"/
|
114
|
+
STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|\\#{NL}|#{ESCAPE})*)\'/
|
115
|
+
STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
|
116
|
+
STATIC_VALUE = /(#{NMCHAR}|#{STRING1_NOINTERP}|\s(?!%)|#[a-f0-9]|[,%]|\.[0-9]|\!important)+(?=[;}])/i
|
117
|
+
|
118
|
+
STATIC_SELECTOR = /(#{NMCHAR}|\s|[,>+*]|[:#.]#{NMSTART})+(?=[{])/i
|
111
119
|
end
|
112
120
|
end
|
113
121
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Sass
|
2
|
+
module SCSS
|
3
|
+
# A subclass of {Parser} that parses code in Sass documents
|
4
|
+
# using some SCSS constructs.
|
5
|
+
# This is necessary because SassScript in Sass supports `!`-style variables,
|
6
|
+
# whereas in SCSS it doesn't.
|
7
|
+
class SassParser < Parser
|
8
|
+
@sass_script_parser = Sass::Script::Parser
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -4,6 +4,8 @@ module Sass
|
|
4
4
|
# that makes them usable by {SCSS::Parser} to parse SassScript.
|
5
5
|
# In particular, the lexer doesn't support `!` for a variable prefix.
|
6
6
|
module ScriptLexer
|
7
|
+
private
|
8
|
+
|
7
9
|
def variable
|
8
10
|
return [:raw, "!important"] if scan(Sass::SCSS::RX::IMPORTANT)
|
9
11
|
_variable(/(\$)(#{Sass::SCSS::RX::IDENT})/)
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Sass
|
2
|
+
module SCSS
|
3
|
+
# A parser for a static SCSS tree.
|
4
|
+
# Parses with SCSS extensions, like nested rules and parent selectors,
|
5
|
+
# but without dynamic SassScript.
|
6
|
+
# This is useful for e.g. \{#parse\_selector parsing selectors}
|
7
|
+
# after resolving the interpolation.
|
8
|
+
class StaticParser < Parser
|
9
|
+
# Parses the text as a selector.
|
10
|
+
#
|
11
|
+
# @param line [Fixnum] The line on which the selector appears.
|
12
|
+
# Used for error reporting
|
13
|
+
# @param filename [String, nil] The file in which the selector appears,
|
14
|
+
# or nil if there is no such file.
|
15
|
+
# Used for error reporting
|
16
|
+
# @return [Selector::CommaSequence] The parsed selector
|
17
|
+
# @raise [Sass::SyntaxError] if there's a syntax error in the selector
|
18
|
+
def parse_selector(line, filename)
|
19
|
+
init_scanner!
|
20
|
+
selectors = [expr!(:_selector)]
|
21
|
+
while tok(/,/)
|
22
|
+
ws = str{ss}
|
23
|
+
selectors << expr!(:_selector)
|
24
|
+
selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members) if ws.include?("\n")
|
25
|
+
end
|
26
|
+
expected("selector") unless @scanner.eos?
|
27
|
+
seq = Selector::CommaSequence.new(selectors)
|
28
|
+
seq.line = line
|
29
|
+
seq.filename = filename
|
30
|
+
seq
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def variable; nil; end
|
36
|
+
def script_value; nil; end
|
37
|
+
def interpolation; nil; end
|
38
|
+
def interp_string; s = tok(STRING) and [s]; end
|
39
|
+
def interp_ident(ident = IDENT); s = tok(ident) and [s]; end
|
40
|
+
def use_css_import?; true; end
|
41
|
+
|
42
|
+
def special_directive(name)
|
43
|
+
return unless name == 'media' || name == 'import'
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,353 @@
|
|
1
|
+
require 'sass/selector/simple'
|
2
|
+
require 'sass/selector/abstract_sequence'
|
3
|
+
require 'sass/selector/comma_sequence'
|
4
|
+
require 'sass/selector/sequence'
|
5
|
+
require 'sass/selector/simple_sequence'
|
6
|
+
|
7
|
+
module Sass
|
8
|
+
# A namespace for nodes in the parse tree for selectors.
|
9
|
+
#
|
10
|
+
# {CommaSequence} is the toplevel seelctor,
|
11
|
+
# representing a comma-separated sequence of {Sequence}s,
|
12
|
+
# such as `foo bar, baz bang`.
|
13
|
+
# {Sequence} is the next level,
|
14
|
+
# representing {SimpleSequence}s separated by combinators (e.g. descendant or child),
|
15
|
+
# such as `foo bar` or `foo > bar baz`.
|
16
|
+
# {SimpleSequence} is a sequence of selectors that all apply to a single element,
|
17
|
+
# such as `foo.bar[attr=val]`.
|
18
|
+
# Finally, {Simple} is the superclass of the simplest selectors,
|
19
|
+
# such as `.foo` or `#bar`.
|
20
|
+
module Selector
|
21
|
+
# A parent-referencing selector (`&` in Sass).
|
22
|
+
# The function of this is to be replaced by the parent selector
|
23
|
+
# in the nested hierarchy.
|
24
|
+
class Parent < Simple
|
25
|
+
# @see Selector#to_a
|
26
|
+
def to_a
|
27
|
+
["&"]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Always raises an exception.
|
31
|
+
#
|
32
|
+
# @raise [Sass::SyntaxError] Parent selectors should be resolved before unification
|
33
|
+
# @see Selector#unify
|
34
|
+
def unify(sels)
|
35
|
+
raise Sass::SyntaxError.new("[BUG] Cannot unify parent selectors.")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# A class selector (e.g. `.foo`).
|
40
|
+
class Class < Simple
|
41
|
+
# The class name.
|
42
|
+
#
|
43
|
+
# @return [Array<String, Sass::Script::Node>]
|
44
|
+
attr_reader :name
|
45
|
+
|
46
|
+
# @param name [Array<String, Sass::Script::Node>] The class name
|
47
|
+
def initialize(name)
|
48
|
+
@name = name
|
49
|
+
end
|
50
|
+
|
51
|
+
# @see Selector#to_a
|
52
|
+
def to_a
|
53
|
+
[".", *@name]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# An id selector (e.g. `#foo`).
|
58
|
+
class Id < Simple
|
59
|
+
# The id name.
|
60
|
+
#
|
61
|
+
# @return [Array<String, Sass::Script::Node>]
|
62
|
+
attr_reader :name
|
63
|
+
|
64
|
+
# @param name [Array<String, Sass::Script::Node>] The id name
|
65
|
+
def initialize(name)
|
66
|
+
@name = name
|
67
|
+
end
|
68
|
+
|
69
|
+
# @see Selector#to_a
|
70
|
+
def to_a
|
71
|
+
["#", *@name]
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns `nil` if `sels` contains an {Id} selector
|
75
|
+
# with a different name than this one.
|
76
|
+
#
|
77
|
+
# @see Selector#unify
|
78
|
+
def unify(sels)
|
79
|
+
return if sels.any? {|sel2| sel2.is_a?(Id) && self.name != sel2.name}
|
80
|
+
super
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# A universal selector (`*` in CSS).
|
85
|
+
class Universal < Simple
|
86
|
+
# The selector namespace.
|
87
|
+
# `nil` means the default namespace,
|
88
|
+
# `[""]` means no namespace,
|
89
|
+
# `["*"]` means any namespace.
|
90
|
+
#
|
91
|
+
# @return [Array<String, Sass::Script::Node>, nil]
|
92
|
+
attr_reader :namespace
|
93
|
+
|
94
|
+
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
95
|
+
def initialize(namespace)
|
96
|
+
@namespace = namespace
|
97
|
+
end
|
98
|
+
|
99
|
+
# @see Selector#to_a
|
100
|
+
def to_a
|
101
|
+
@namespace ? @namespace + ["|*"] : ["*"]
|
102
|
+
end
|
103
|
+
|
104
|
+
# Unification of a universal selector is somewhat complicated,
|
105
|
+
# especially when a namespace is specified.
|
106
|
+
# If there is no namespace specified
|
107
|
+
# or any namespace is specified (namespace `"*"`),
|
108
|
+
# then `sel` is returned without change
|
109
|
+
# (unless it's empty, in which case `"*"` is required).
|
110
|
+
#
|
111
|
+
# If a namespace is specified
|
112
|
+
# but `sel` does not specify a namespace,
|
113
|
+
# then the given namespace is applied to `sel`,
|
114
|
+
# either by adding this {Universal} selector
|
115
|
+
# or applying this namespace to an existing {Element} selector.
|
116
|
+
#
|
117
|
+
# If both this selector *and* `sel` specify namespaces,
|
118
|
+
# those namespaces are unified via {Simple#unify_namespaces}
|
119
|
+
# and the unified namespace is used, if possible.
|
120
|
+
#
|
121
|
+
# @todo There are lots of cases that this documentation specifies;
|
122
|
+
# make sure we thoroughly test **all of them**.
|
123
|
+
# @todo Keep track of whether a default namespace has been declared
|
124
|
+
# and handle namespace-unspecified selectors accordingly.
|
125
|
+
# @todo If any branch of a CommaSequence ends up being just `"*"`,
|
126
|
+
# then all other branches should be eliminated
|
127
|
+
#
|
128
|
+
# @see Selector#unify
|
129
|
+
def unify(sels)
|
130
|
+
name =
|
131
|
+
case sels.first
|
132
|
+
when Universal; :universal
|
133
|
+
when Element; sels.first.name
|
134
|
+
else
|
135
|
+
return [self] + sels unless namespace.nil? || namespace == ['*']
|
136
|
+
return sels unless sels.empty?
|
137
|
+
return [self]
|
138
|
+
end
|
139
|
+
|
140
|
+
ns, accept = unify_namespaces(namespace, sels.first.namespace)
|
141
|
+
return unless accept
|
142
|
+
[name == :universal ? Universal.new(ns) : Element.new(name, ns)] + sels[1..-1]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# An element selector (e.g. `h1`).
|
147
|
+
class Element < Simple
|
148
|
+
# The element name.
|
149
|
+
#
|
150
|
+
# @return [Array<String, Sass::Script::Node>]
|
151
|
+
attr_reader :name
|
152
|
+
|
153
|
+
# The selector namespace.
|
154
|
+
# `nil` means the default namespace,
|
155
|
+
# `[""]` means no namespace,
|
156
|
+
# `["*"]` means any namespace.
|
157
|
+
#
|
158
|
+
# @return [Array<String, Sass::Script::Node>, nil]
|
159
|
+
attr_reader :namespace
|
160
|
+
|
161
|
+
# @param name [Array<String, Sass::Script::Node>] The element name
|
162
|
+
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
163
|
+
def initialize(name, namespace)
|
164
|
+
@name = name
|
165
|
+
@namespace = namespace
|
166
|
+
end
|
167
|
+
|
168
|
+
# @see Selector#to_a
|
169
|
+
def to_a
|
170
|
+
@namespace ? @namespace + ["|"] + @name : @name
|
171
|
+
end
|
172
|
+
|
173
|
+
# Unification of an element selector is somewhat complicated,
|
174
|
+
# especially when a namespace is specified.
|
175
|
+
# First, if `sel` contains another {Element} with a different \{#name},
|
176
|
+
# then the selectors can't be unified and `nil` is returned.
|
177
|
+
#
|
178
|
+
# Otherwise, if `sel` doesn't specify a namespace,
|
179
|
+
# or it specifies any namespace (via `"*"`),
|
180
|
+
# then it's returned with this element selector
|
181
|
+
# (e.g. `.foo` becomes `a.foo` or `svg|a.foo`).
|
182
|
+
# Similarly, if this selector doesn't specify a namespace,
|
183
|
+
# the namespace from `sel` is used.
|
184
|
+
#
|
185
|
+
# If both this selector *and* `sel` specify namespaces,
|
186
|
+
# those namespaces are unified via {Simple#unify_namespaces}
|
187
|
+
# and the unified namespace is used, if possible.
|
188
|
+
#
|
189
|
+
# @todo There are lots of cases that this documentation specifies;
|
190
|
+
# make sure we thoroughly test **all of them**.
|
191
|
+
# @todo Keep track of whether a default namespace has been declared
|
192
|
+
# and handle namespace-unspecified selectors accordingly.
|
193
|
+
#
|
194
|
+
# @see Selector#unify
|
195
|
+
def unify(sels)
|
196
|
+
case sels.first
|
197
|
+
when Universal;
|
198
|
+
when Element; return unless name == sels.first.name
|
199
|
+
else return [self] + sels
|
200
|
+
end
|
201
|
+
|
202
|
+
ns, accept = unify_namespaces(namespace, sels.first.namespace)
|
203
|
+
return unless accept
|
204
|
+
[Element.new(name, ns)] + sels[1..-1]
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Selector interpolation (`#{}` in Sass).
|
209
|
+
class Interpolation < Simple
|
210
|
+
# The script to run.
|
211
|
+
#
|
212
|
+
# @return [Sass::Script::Node]
|
213
|
+
attr_reader :script
|
214
|
+
|
215
|
+
# @param script [Sass::Script::Node] The script to run
|
216
|
+
def initialize(script)
|
217
|
+
@script = script
|
218
|
+
end
|
219
|
+
|
220
|
+
# @see Selector#to_a
|
221
|
+
def to_a
|
222
|
+
[@script]
|
223
|
+
end
|
224
|
+
|
225
|
+
# Always raises an exception.
|
226
|
+
#
|
227
|
+
# @raise [Sass::SyntaxError] Interpolation selectors should be resolved before unification
|
228
|
+
# @see Selector#unify
|
229
|
+
def unify(sels)
|
230
|
+
raise Sass::SyntaxError.new("[BUG] Cannot unify interpolation selectors.")
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# An attribute selector (e.g. `[href^="http://"]`).
|
235
|
+
class Attribute < Simple
|
236
|
+
# The attribute name.
|
237
|
+
#
|
238
|
+
# @return [Array<String, Sass::Script::Node>]
|
239
|
+
attr_reader :name
|
240
|
+
|
241
|
+
# The attribute namespace.
|
242
|
+
# `nil` means the default namespace,
|
243
|
+
# `[""]` means no namespace,
|
244
|
+
# `["*"]` means any namespace.
|
245
|
+
#
|
246
|
+
# @return [Array<String, Sass::Script::Node>, nil]
|
247
|
+
attr_reader :namespace
|
248
|
+
|
249
|
+
# The matching operator, e.g. `"="` or `"^="`.
|
250
|
+
#
|
251
|
+
# @return [String]
|
252
|
+
attr_reader :operator
|
253
|
+
|
254
|
+
# The right-hand side of the operator.
|
255
|
+
#
|
256
|
+
# @return [Array<String, Sass::Script::Node>]
|
257
|
+
attr_reader :value
|
258
|
+
|
259
|
+
# @param name [Array<String, Sass::Script::Node>] The attribute name
|
260
|
+
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
261
|
+
# @param operator [String] The matching operator, e.g. `"="` or `"^="`
|
262
|
+
# @param value [Array<String, Sass::Script::Node>] See \{#value}
|
263
|
+
def initialize(name, namespace, operator, value)
|
264
|
+
@name = name
|
265
|
+
@namespace = namespace
|
266
|
+
@operator = operator
|
267
|
+
@value = value
|
268
|
+
end
|
269
|
+
|
270
|
+
# @see Selector#to_a
|
271
|
+
def to_a
|
272
|
+
res = ["["]
|
273
|
+
res.concat(@namespace) << "|" if @namespace
|
274
|
+
res.concat @name
|
275
|
+
(res << @operator).concat @value if @value
|
276
|
+
res << "]"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`) selector.
|
281
|
+
# It can have arguments (e.g. `:nth-child(2n+1)`).
|
282
|
+
class Pseudo < Simple
|
283
|
+
# The type of the selector.
|
284
|
+
# `:class` if this is a pseudoclass selector,
|
285
|
+
# `:element` if it's a pseudoelement.
|
286
|
+
#
|
287
|
+
# @return [Symbol]
|
288
|
+
attr_reader :type
|
289
|
+
|
290
|
+
# The name of the selector.
|
291
|
+
#
|
292
|
+
# @return [Array<String, Sass::Script::Node>]
|
293
|
+
attr_reader :name
|
294
|
+
|
295
|
+
# The argument to the selector,
|
296
|
+
# or `nil` if no argument was given.
|
297
|
+
#
|
298
|
+
# This may include SassScript nodes that will be run during resolution.
|
299
|
+
# Note that this should not include SassScript nodes
|
300
|
+
# after resolution has taken place.
|
301
|
+
#
|
302
|
+
# @return [Array<String, Sass::Script::Node>, nil]
|
303
|
+
attr_reader :arg
|
304
|
+
|
305
|
+
# @param type [Symbol] See \{#type}
|
306
|
+
# @param name [Array<String, Sass::Script::Node>] The name of the selector
|
307
|
+
# @param arg [nil, Array<String, Sass::Script::Node>] The argument to the selector,
|
308
|
+
# or nil if no argument was given
|
309
|
+
def initialize(type, name, arg)
|
310
|
+
@type = type
|
311
|
+
@name = name
|
312
|
+
@arg = arg
|
313
|
+
end
|
314
|
+
|
315
|
+
# @see Selector#to_a
|
316
|
+
def to_a
|
317
|
+
res = [@type == :class ? ":" : "::"] + @name
|
318
|
+
(res << "(").concat(Haml::Util.strip_string_array(@arg)) << ")" if @arg
|
319
|
+
res
|
320
|
+
end
|
321
|
+
|
322
|
+
# Returns `nil` if this is a pseudoclass selector
|
323
|
+
# and `sels` contains a pseudoclass selector different than this one.
|
324
|
+
#
|
325
|
+
# @see Selector#unify
|
326
|
+
def unify(sels)
|
327
|
+
return if type == :element && sels.any? do |sel|
|
328
|
+
sel.is_a?(Pseudo) && sel.type == :element &&
|
329
|
+
(sel.name != self.name || sel.arg != self.arg)
|
330
|
+
end
|
331
|
+
super
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# A negation pseudoclass selector (e.g. `:not(.foo)`).
|
336
|
+
class Negation < Simple
|
337
|
+
# The selector to negate.
|
338
|
+
#
|
339
|
+
# @return [Selector]
|
340
|
+
attr_reader :selector
|
341
|
+
|
342
|
+
# @param [Selector] The selector to negate
|
343
|
+
def initialize(selector)
|
344
|
+
@selector = selector
|
345
|
+
end
|
346
|
+
|
347
|
+
# @see Selector#to_a
|
348
|
+
def to_a
|
349
|
+
[":not("] + @selector.to_a + [")"]
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Sass
|
2
|
+
module Selector
|
3
|
+
# The abstract parent class of the various selector sequence classes.
|
4
|
+
#
|
5
|
+
# All subclasses should implement a `members` method
|
6
|
+
# that returns an array of object that respond to `#line=` and `#filename=`.
|
7
|
+
class AbstractSequence
|
8
|
+
# The line of the Sass template on which this selector was declared.
|
9
|
+
#
|
10
|
+
# @return [Fixnum]
|
11
|
+
attr_reader :line
|
12
|
+
|
13
|
+
# The name of the file in which this selector was declared.
|
14
|
+
#
|
15
|
+
# @return [String, nil]
|
16
|
+
attr_reader :filename
|
17
|
+
|
18
|
+
# Sets the line of the Sass template on which this selector was declared.
|
19
|
+
# This also sets the line for all child selectors.
|
20
|
+
#
|
21
|
+
# @param line [Fixnum]
|
22
|
+
# @return [Fixnum]
|
23
|
+
def line=(line)
|
24
|
+
members.each {|m| m.line = line}
|
25
|
+
@line = line
|
26
|
+
end
|
27
|
+
|
28
|
+
# Sets the name of the file in which this selector was declared,
|
29
|
+
# or `nil` if it was not declared in a file (e.g. on stdin).
|
30
|
+
# This also sets the filename for all child selectors.
|
31
|
+
#
|
32
|
+
# @param filename [String, nil]
|
33
|
+
# @return [String, nil]
|
34
|
+
def filename=(filename)
|
35
|
+
members.each {|m| m.filename = filename}
|
36
|
+
@filename = filename
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|