csspool 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.DS_Store +0 -0
- data/CHANGELOG.txt +10 -0
- data/Manifest.txt +36 -2
- data/README.txt +4 -4
- data/Rakefile +1 -1
- data/lib/css/sac/conditions/attribute_condition.rb +52 -0
- data/lib/css/sac/conditions/begin_hyphen_condition.rb +22 -0
- data/lib/css/sac/conditions/class_condition.rb +22 -0
- data/lib/css/sac/conditions/combinator_condition.rb +36 -0
- data/lib/css/sac/conditions/condition.rb +27 -0
- data/lib/css/sac/conditions/id_condition.rb +27 -0
- data/lib/css/sac/conditions/one_of_condition.rb +22 -0
- data/lib/css/sac/conditions/pseudo_class_condition.rb +24 -0
- data/lib/css/sac/conditions.rb +5 -0
- data/lib/css/sac/document_handler.rb +1 -1
- data/lib/css/sac/parser.rb +5 -3
- data/lib/css/sac/selectors/child_selector.rb +36 -0
- data/lib/css/sac/selectors/conditional_selector.rb +43 -0
- data/lib/css/sac/selectors/descendant_selector.rb +36 -0
- data/lib/css/sac/selectors/element_selector.rb +35 -0
- data/lib/css/sac/selectors/selector.rb +23 -0
- data/lib/css/sac/selectors/sibling_selector.rb +35 -0
- data/lib/css/sac/selectors/simple_selector.rb +25 -0
- data/lib/css/sac/selectors.rb +3 -85
- data/lib/css/sac/visitable.rb +104 -0
- data/lib/parser.y +24 -15
- data/test/condition_test_case.rb +6 -0
- data/test/helper.rb +2 -0
- data/test/selector_test_case.rb +20 -0
- data/test/test_attribute_condition.rb +30 -0
- data/test/test_begin_hyphen_condition.rb +15 -0
- data/test/test_child_selector.rb +48 -0
- data/test/test_class_condition.rb +15 -0
- data/test/test_combinator_condition.rb +29 -0
- data/test/test_condition.rb +13 -0
- data/test/test_conditional_selector.rb +29 -0
- data/test/test_descendant_selector.rb +52 -0
- data/test/test_element_selector.rb +22 -0
- data/test/test_id_condition.rb +16 -0
- data/test/test_one_of_condition.rb +15 -0
- data/test/test_parser.rb +58 -0
- data/test/test_selector.rb +19 -0
- data/test/test_selector_as_string.rb +11 -0
- data/test/test_selector_parser.rb +2 -2
- data/test/test_sibling_selector.rb +33 -0
- data/test/test_simple_selector.rb +9 -0
- data/test/test_specificity.rb +76 -0
- data/test/test_xpath.rb +105 -0
- metadata +38 -4
- data/lib/css/sac/attribute_condition.rb +0 -78
- data/lib/css/sac/condition.rb +0 -21
data/lib/css/sac/selectors.rb
CHANGED
@@ -1,87 +1,5 @@
|
|
1
|
-
|
2
|
-
module SAC
|
3
|
-
class Selector
|
4
|
-
attr_reader :selector_type
|
5
|
-
end
|
1
|
+
require "css/sac/selectors/selector"
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
@selector_type = :SAC_ANY_NODE_SELECTOR
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_css
|
13
|
-
case @selector_type
|
14
|
-
when :SAC_ANY_NODE_SELECTOR
|
15
|
-
'*'
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class ElementSelector < SimpleSelector
|
21
|
-
attr_reader :local_name
|
22
|
-
alias :name :local_name
|
23
|
-
|
24
|
-
def initialize(name)
|
25
|
-
super()
|
26
|
-
@selector_type = :SAC_ELEMENT_NODE_SELECTOR
|
27
|
-
@local_name = name
|
28
|
-
end
|
29
|
-
|
30
|
-
def to_css
|
31
|
-
local_name
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class ConditionalSelector < SimpleSelector
|
36
|
-
attr_accessor :condition, :simple_selector
|
37
|
-
alias :selector :simple_selector
|
38
|
-
|
39
|
-
def initialize(selector, condition)
|
40
|
-
@condition = condition
|
41
|
-
@simple_selector = selector
|
42
|
-
@selector_type = :SAC_CONDITIONAL_SELECTOR
|
43
|
-
end
|
44
|
-
|
45
|
-
def to_css
|
46
|
-
[selector, condition].map { |x|
|
47
|
-
x ? x.to_css : ''
|
48
|
-
}.join('')
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
class DescendantSelector < SimpleSelector
|
53
|
-
attr_accessor :ancestor_selector, :simple_selector
|
54
|
-
alias :selector :simple_selector
|
55
|
-
|
56
|
-
def initialize(ancestor, selector, type)
|
57
|
-
@ancestor_selector = ancestor
|
58
|
-
@simple_selector = selector
|
59
|
-
@selector_type = type
|
60
|
-
end
|
61
|
-
|
62
|
-
def to_css
|
63
|
-
descent_token =
|
64
|
-
case @selector_type
|
65
|
-
when :SAC_CHILD_SELECTOR
|
66
|
-
' > '
|
67
|
-
when :SAC_DESCENDANT_SELECTOR
|
68
|
-
' '
|
69
|
-
end
|
70
|
-
ancestor_selector.to_css + descent_token + selector.to_css
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
class SiblingSelector < SimpleSelector
|
75
|
-
attr_accessor :selector, :sibling_selector
|
76
|
-
def initialize(selector, sibling)
|
77
|
-
@selector = selector
|
78
|
-
@sibling_selector = sibling
|
79
|
-
@selector_type = :SAC_DIRECT_ADJACENT_SELECTOR
|
80
|
-
end
|
81
|
-
|
82
|
-
def to_css
|
83
|
-
selector.to_css + ' + ' + sibling_selector.to_css
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
3
|
+
%w(simple child conditional descendant element sibling).each do |type|
|
4
|
+
require "css/sac/selectors/#{type}_selector"
|
87
5
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module CSS
|
2
|
+
module SAC
|
3
|
+
module Visitable # :nodoc:
|
4
|
+
# Based off the visitor pattern from RubyGarden
|
5
|
+
def accept(visitor, &block)
|
6
|
+
klass = self.class.ancestors.find { |klass|
|
7
|
+
visitor.respond_to?("visit_#{klass.name.split(/::/)[-1]}")
|
8
|
+
}
|
9
|
+
|
10
|
+
if klass
|
11
|
+
visitor.send(:"visit_#{klass.name.split(/::/)[-1]}", self, &block)
|
12
|
+
else
|
13
|
+
raise "No visitor for '#{self.class}'"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class MatchesVisitor
|
19
|
+
def initialize(node)
|
20
|
+
@node = node
|
21
|
+
end
|
22
|
+
|
23
|
+
def accept(target)
|
24
|
+
target.accept(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
def visit_SimpleSelector(o)
|
28
|
+
return false if @node.nil?
|
29
|
+
return false unless @node.respond_to?(:name)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def visit_ElementSelector(o)
|
34
|
+
return false unless visit_SimpleSelector(o) # *sigh*
|
35
|
+
o.name == @node.name
|
36
|
+
end
|
37
|
+
|
38
|
+
def visit_ChildSelector(o)
|
39
|
+
return false unless visit_SimpleSelector(o) # *sigh*
|
40
|
+
return false unless @node.respond_to?(:parent)
|
41
|
+
return false if @node.parent.nil?
|
42
|
+
return false unless o.selector.accept(self)
|
43
|
+
@node = @node.parent
|
44
|
+
o.parent.accept(self)
|
45
|
+
end
|
46
|
+
|
47
|
+
def visit_DescendantSelector(o)
|
48
|
+
return false unless visit_SimpleSelector(o) # *sigh*
|
49
|
+
return false unless @node.respond_to?(:parent)
|
50
|
+
return false if @node.parent.nil?
|
51
|
+
return false unless o.selector.accept(self)
|
52
|
+
|
53
|
+
@node = @node.parent
|
54
|
+
loop {
|
55
|
+
return true if o.ancestor.accept(self)
|
56
|
+
return false unless @node.respond_to?(:parent)
|
57
|
+
@node = @node.parent
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def visit_SiblingSelector(o)
|
62
|
+
return false unless visit_SimpleSelector(o) # *sigh*
|
63
|
+
return false unless @node.respond_to?(:next_sibling)
|
64
|
+
return false if @node.next_sibling.nil?
|
65
|
+
return false unless o.selector.accept(self)
|
66
|
+
@node = @node.next_sibling
|
67
|
+
o.sibling.accept(self)
|
68
|
+
end
|
69
|
+
|
70
|
+
def visit_ConditionalSelector(o)
|
71
|
+
return false unless visit_SimpleSelector(o) # *sigh*
|
72
|
+
o.selector.accept(self) && o.condition.accept(self)
|
73
|
+
end
|
74
|
+
|
75
|
+
def visit_AttributeCondition(o)
|
76
|
+
return false unless @node.respond_to?(:attributes)
|
77
|
+
return false unless @node.attributes[o.local_name]
|
78
|
+
@node.attributes[o.local_name] == o.value
|
79
|
+
end
|
80
|
+
|
81
|
+
def visit_BeginHyphenCondition(o)
|
82
|
+
return false unless @node.respond_to?(:attributes)
|
83
|
+
return false unless @node.attributes[o.local_name]
|
84
|
+
@node.attributes[o.local_name] =~ /^#{o.value}/
|
85
|
+
end
|
86
|
+
|
87
|
+
def visit_CombinatorCondition(o)
|
88
|
+
o.first.accept(self) && o.second.accept(self)
|
89
|
+
end
|
90
|
+
|
91
|
+
def visit_OneOfCondition(o)
|
92
|
+
return false unless @node.respond_to?(:attributes)
|
93
|
+
return false unless @node.attributes[o.local_name]
|
94
|
+
@node.attributes[o.local_name].split.any? { |attribute|
|
95
|
+
attribute == o.value
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
def visit_PseudoClassCondition(o)
|
100
|
+
false # Fuck pseudo classes. --Aaron
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/parser.y
CHANGED
@@ -23,10 +23,6 @@ rule
|
|
23
23
|
self.document_handler.import_style(val[2], val[4] || [])
|
24
24
|
}
|
25
25
|
;
|
26
|
-
optional_ignorable_at
|
27
|
-
: ignorable_at
|
28
|
-
|
|
29
|
-
;
|
30
26
|
ignorable_at
|
31
27
|
: '@' IDENT s_0toN string_or_uri s_0toN medium_0toN ';' s_0toN {
|
32
28
|
self.document_handler.ignorable_at_rule(val[1])
|
@@ -146,16 +142,19 @@ rule
|
|
146
142
|
simple_selector_1toN
|
147
143
|
: simple_selector combinator simple_selector_1toN {
|
148
144
|
result =
|
149
|
-
|
145
|
+
case val[1]
|
146
|
+
when :SAC_DIRECT_ADJACENT_SELECTOR
|
150
147
|
SiblingSelector.new(val.first, val[2])
|
151
|
-
|
152
|
-
DescendantSelector.new(val.first, val[2]
|
148
|
+
when :SAC_DESCENDANT_SELECTOR
|
149
|
+
DescendantSelector.new(val.first, val[2])
|
150
|
+
when :SAC_CHILD_SELECTOR
|
151
|
+
ChildSelector.new(val.first, val[2])
|
153
152
|
end
|
154
153
|
}
|
155
154
|
| simple_selector
|
156
155
|
;
|
157
156
|
class
|
158
|
-
: '.' IDENT { result =
|
157
|
+
: '.' IDENT { result = ClassCondition.new(val[1]) }
|
159
158
|
;
|
160
159
|
element_name
|
161
160
|
: IDENT { result = ElementSelector.new(val.first) }
|
@@ -163,13 +162,14 @@ rule
|
|
163
162
|
;
|
164
163
|
attrib
|
165
164
|
: '[' s_0toN IDENT s_0toN attrib_val_0or1 ']' {
|
166
|
-
result = AttributeCondition.
|
165
|
+
result = AttributeCondition.build(val[2], val[4])
|
167
166
|
}
|
168
167
|
;
|
169
168
|
pseudo
|
170
|
-
: ':'
|
171
|
-
|
172
|
-
|
169
|
+
: ':' function {
|
170
|
+
result = PseudoClassCondition.new(val[1])
|
171
|
+
}
|
172
|
+
| ':' IDENT { result = PseudoClassCondition.new(val[1]) }
|
173
173
|
;
|
174
174
|
declaration
|
175
175
|
: property ':' s_0toN expr prio_0or1 {
|
@@ -203,7 +203,7 @@ rule
|
|
203
203
|
|
|
204
204
|
;
|
205
205
|
expr
|
206
|
-
: term operator expr { result = val }
|
206
|
+
: term operator expr { result = [val[0], val.last] }
|
207
207
|
| term
|
208
208
|
;
|
209
209
|
term
|
@@ -226,7 +226,9 @@ rule
|
|
226
226
|
| FREQ s_0toN
|
227
227
|
;
|
228
228
|
function
|
229
|
-
: FUNCTION s_0toN expr ')' s_0toN {
|
229
|
+
: FUNCTION s_0toN expr ')' s_0toN {
|
230
|
+
result = Function.new(val[0], val[2].flatten)
|
231
|
+
}
|
230
232
|
| FUNCTION s_0toN expr error ')' s_0toN { yyerrok; result = [val[0], val[2], val[3]] }
|
231
233
|
;
|
232
234
|
hexcolor
|
@@ -255,7 +257,7 @@ rule
|
|
255
257
|
| pseudo
|
256
258
|
;
|
257
259
|
attribute_id
|
258
|
-
: HASH { result =
|
260
|
+
: HASH { result = IDCondition.new(val.first) }
|
259
261
|
;
|
260
262
|
attrib_val_0or1
|
261
263
|
: eql_incl_dash s_0toN IDENT s_0toN { result = [val.first, val[2]] }
|
@@ -285,3 +287,10 @@ rule
|
|
285
287
|
|
|
286
288
|
;
|
287
289
|
end
|
290
|
+
|
291
|
+
---- header
|
292
|
+
require "css/sac/conditions"
|
293
|
+
require "css/sac/selectors"
|
294
|
+
|
295
|
+
include CSS::SAC::Conditions
|
296
|
+
include CSS::SAC::Selectors
|
data/test/helper.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
class SelectorTestCase < Test::Unit::TestCase
|
2
|
+
include CSS::SAC::Selectors
|
3
|
+
Node = Struct.new(:name, :parent, :child, :next_sibling, :attributes)
|
4
|
+
NoParentNode = Struct.new(:name)
|
5
|
+
|
6
|
+
def parent_child_tree(*args)
|
7
|
+
nodes = args.map { |name|
|
8
|
+
n = Node.new
|
9
|
+
n.name = name
|
10
|
+
n
|
11
|
+
}
|
12
|
+
nodes.each_with_index do |n,i|
|
13
|
+
n.child = nodes[i + 1] if i < nodes.length
|
14
|
+
n.parent = nodes[i - 1] if i > 0
|
15
|
+
end
|
16
|
+
nodes.last
|
17
|
+
end
|
18
|
+
|
19
|
+
undef :default_test
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class AttributeConditionTest < ConditionTestCase
|
4
|
+
def test_equals2
|
5
|
+
first = AttributeCondition.new(1, 1, 1)
|
6
|
+
second = AttributeCondition.new(1, 1, 1)
|
7
|
+
assert_equal first, second
|
8
|
+
|
9
|
+
third = AttributeCondition.new(1,1,2)
|
10
|
+
assert_not_equal first, third
|
11
|
+
|
12
|
+
fourth = AttributeCondition.new(1,2,1)
|
13
|
+
assert_not_equal first, fourth
|
14
|
+
|
15
|
+
fifth = AttributeCondition.new(2,1,1)
|
16
|
+
assert_not_equal first, fifth
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_equals_tilde
|
20
|
+
attribute = AttributeCondition.new('class', 'foo', true)
|
21
|
+
node = Node.new('p')
|
22
|
+
node.attributes = { 'class' => 'foo' }
|
23
|
+
|
24
|
+
assert attribute =~ node
|
25
|
+
|
26
|
+
node.attributes = { 'class' => 'bar' }
|
27
|
+
assert(!(attribute =~ node))
|
28
|
+
assert(!(attribute =~ 1))
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class BeginHyphenConditionTest < ConditionTestCase
|
4
|
+
def test_tilde_equals
|
5
|
+
attribute = BeginHyphenCondition.new('class', 'foo')
|
6
|
+
node = Node.new('p')
|
7
|
+
node.attributes = { 'class' => 'foobar' }
|
8
|
+
|
9
|
+
assert attribute =~ node
|
10
|
+
|
11
|
+
node.attributes = { 'class' => 'barfoo' }
|
12
|
+
assert(!(attribute =~ node))
|
13
|
+
assert(!(attribute =~ 1))
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class ChildSelectorTest < SelectorTestCase
|
4
|
+
def test_equals2
|
5
|
+
first = ChildSelector.new(1,1)
|
6
|
+
second = ChildSelector.new(1,1)
|
7
|
+
assert_equal first, second
|
8
|
+
|
9
|
+
third = ChildSelector.new(1,2)
|
10
|
+
assert_not_equal first, third
|
11
|
+
|
12
|
+
fourth = ChildSelector.new(2,1)
|
13
|
+
assert_not_equal first, fourth
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_equals_tilde
|
17
|
+
parent = ElementSelector.new('div')
|
18
|
+
child = ElementSelector.new('p')
|
19
|
+
sel = ChildSelector.new(parent, child)
|
20
|
+
|
21
|
+
node = parent_child_tree('div', 'p')
|
22
|
+
assert sel =~ node
|
23
|
+
|
24
|
+
node2 = parent_child_tree('body', 'div', 'p')
|
25
|
+
assert sel =~ node2
|
26
|
+
|
27
|
+
failing = parent_child_tree('p', 'div')
|
28
|
+
assert(! (sel =~ failing))
|
29
|
+
assert(! (sel =~ NoParentNode.new('div')))
|
30
|
+
assert(! (sel =~ Node.new('div', nil, nil)))
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_many_child
|
34
|
+
@sac = CSS::SAC::Parser.new()
|
35
|
+
class << @sac.document_handler
|
36
|
+
attr_accessor :selectors
|
37
|
+
alias :start_selector :selectors=
|
38
|
+
end
|
39
|
+
|
40
|
+
@sac.parse('div > h1 > h2 { }')
|
41
|
+
selectors = @sac.document_handler.selectors
|
42
|
+
assert_equal(1, selectors.length)
|
43
|
+
|
44
|
+
sel = selectors.first
|
45
|
+
node = parent_child_tree('div', 'h1', 'h2')
|
46
|
+
assert sel =~ node
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class ClassConditionTest < ConditionTestCase
|
4
|
+
def test_tilde_equals
|
5
|
+
attribute = ClassCondition.new('foo')
|
6
|
+
node = Node.new('p')
|
7
|
+
node.attributes = { 'class' => 'foo' }
|
8
|
+
|
9
|
+
assert attribute =~ node
|
10
|
+
|
11
|
+
node.attributes = { 'class' => 'barfoo' }
|
12
|
+
assert(!(attribute =~ node))
|
13
|
+
assert(!(attribute =~ 1))
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class CombinatorConditionTest < ConditionTestCase
|
4
|
+
def test_equals2
|
5
|
+
first = CombinatorCondition.new(1,1)
|
6
|
+
second = CombinatorCondition.new(1,1)
|
7
|
+
assert_equal first, second
|
8
|
+
|
9
|
+
third = CombinatorCondition.new(1,2)
|
10
|
+
assert_not_equal first, third
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_equals_tilde
|
14
|
+
first = ClassCondition.new('foo')
|
15
|
+
second = AttributeCondition.new('name', 'aaron', true)
|
16
|
+
combinator_condition = CombinatorCondition.new(first, second)
|
17
|
+
|
18
|
+
node = Node.new('p')
|
19
|
+
node.attributes = { 'class' => 'foo', 'name' => 'aaron' }
|
20
|
+
|
21
|
+
assert combinator_condition =~ node
|
22
|
+
|
23
|
+
node.attributes = { 'class' => 'bar', 'name' => 'aaron' }
|
24
|
+
assert(!(combinator_condition =~ node))
|
25
|
+
|
26
|
+
node.attributes = { 'class' => 'foo', 'name' => 'bar' }
|
27
|
+
assert(!(combinator_condition =~ node))
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class ConditionTest < ConditionTestCase
|
4
|
+
def test_equals2
|
5
|
+
first = Condition.new(1)
|
6
|
+
second = Condition.new(1)
|
7
|
+
assert_equal first, second
|
8
|
+
|
9
|
+
third = Condition.new(2)
|
10
|
+
assert_not_equal first, third
|
11
|
+
assert_not_equal first, 1
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class ConditionalSelectorTest < SelectorTestCase
|
4
|
+
def test_equals2
|
5
|
+
first = ConditionalSelector.new(1,1)
|
6
|
+
second = ConditionalSelector.new(1,1)
|
7
|
+
assert_equal first, second
|
8
|
+
|
9
|
+
third = ConditionalSelector.new(1,2)
|
10
|
+
assert_not_equal first, third
|
11
|
+
|
12
|
+
fourth = ConditionalSelector.new(2,1)
|
13
|
+
assert_not_equal first, fourth
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_equals_tilde
|
17
|
+
attribute = AttributeCondition.new('class', 'foo', true)
|
18
|
+
div = ElementSelector.new('div')
|
19
|
+
sel = ConditionalSelector.new(div, attribute)
|
20
|
+
|
21
|
+
node = Node.new('div')
|
22
|
+
node.attributes = { 'class' => 'foo' }
|
23
|
+
|
24
|
+
assert sel =~ node
|
25
|
+
|
26
|
+
node.attributes = { 'class' => 'bar' }
|
27
|
+
assert(!(sel =~ node))
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class DescendantSelectorTest < SelectorTestCase
|
4
|
+
def test_equals2
|
5
|
+
first = DescendantSelector.new(1,1)
|
6
|
+
second = DescendantSelector.new(1,1)
|
7
|
+
assert_equal first, second
|
8
|
+
|
9
|
+
third = DescendantSelector.new(1,2)
|
10
|
+
assert_not_equal first, third
|
11
|
+
|
12
|
+
fourth = DescendantSelector.new(2,1)
|
13
|
+
assert_not_equal first, fourth
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_equals_tilde
|
17
|
+
parent = ElementSelector.new('div')
|
18
|
+
child = ElementSelector.new('p')
|
19
|
+
sel = DescendantSelector.new(parent, child)
|
20
|
+
|
21
|
+
node = parent_child_tree('div', 'p')
|
22
|
+
assert sel =~ node
|
23
|
+
|
24
|
+
node2 = parent_child_tree('body', 'div', 'p')
|
25
|
+
assert sel =~ node2
|
26
|
+
|
27
|
+
node3 = parent_child_tree('body', 'div', 'table', 'tr', 'td', 'p')
|
28
|
+
assert sel =~ node3
|
29
|
+
|
30
|
+
failing = parent_child_tree('p', 'div')
|
31
|
+
assert(! (sel =~ failing))
|
32
|
+
assert(! (sel =~ NoParentNode.new('div')))
|
33
|
+
assert(! (sel =~ Node.new('div', nil, nil)))
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_many_descendants
|
37
|
+
@sac = CSS::SAC::Parser.new()
|
38
|
+
class << @sac.document_handler
|
39
|
+
attr_accessor :selectors
|
40
|
+
alias :start_selector :selectors=
|
41
|
+
end
|
42
|
+
|
43
|
+
@sac.parse('div h1 h2 { }')
|
44
|
+
selectors = @sac.document_handler.selectors
|
45
|
+
assert_equal(1, selectors.length)
|
46
|
+
|
47
|
+
sel = selectors.first
|
48
|
+
node = parent_child_tree('body', 'div', 'p', 'h1', 'p', 'h2')
|
49
|
+
assert sel =~ node
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class ElementSelectorTest < SelectorTestCase
|
4
|
+
def test_equals2
|
5
|
+
first = ElementSelector.new(1)
|
6
|
+
second = ElementSelector.new(1)
|
7
|
+
assert_equal first, second
|
8
|
+
|
9
|
+
third = ElementSelector.new(2)
|
10
|
+
assert_not_equal first, third
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_equals_tilde
|
14
|
+
div = ElementSelector.new('div')
|
15
|
+
node = Node.new
|
16
|
+
node.name = 'div'
|
17
|
+
|
18
|
+
assert div =~ node
|
19
|
+
assert(!(div =~ nil))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class IdConditionTest < ConditionTestCase
|
4
|
+
def test_equals_tilde
|
5
|
+
attribute = IDCondition.new('some_id')
|
6
|
+
node = Node.new('p')
|
7
|
+
node.attributes = { 'id' => 'some_id' }
|
8
|
+
|
9
|
+
assert attribute =~ node
|
10
|
+
|
11
|
+
node.attributes = { 'id' => 'different' }
|
12
|
+
assert(!(attribute =~ node))
|
13
|
+
assert(!(attribute =~ 1))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/helper"
|
2
|
+
|
3
|
+
class OneOfConditionTest < ConditionTestCase
|
4
|
+
def test_equals_tilde
|
5
|
+
attribute = OneOfCondition.new('class', 'foo')
|
6
|
+
node = Node.new('p')
|
7
|
+
node.attributes = { 'class' => 'aaron foo' }
|
8
|
+
|
9
|
+
assert attribute =~ node
|
10
|
+
|
11
|
+
node.attributes = { 'class' => 'bar' }
|
12
|
+
assert(!(attribute =~ node))
|
13
|
+
assert(!(attribute =~ 1))
|
14
|
+
end
|
15
|
+
end
|
data/test/test_parser.rb
CHANGED
@@ -41,6 +41,14 @@ class ParserTest < Test::Unit::TestCase
|
|
41
41
|
flexmock_verify
|
42
42
|
end
|
43
43
|
|
44
|
+
def test_at_import_many_media
|
45
|
+
flexmock(@sac.document_handler).
|
46
|
+
should_receive(:import_style).ordered.
|
47
|
+
with('"subs.css"', ['paper', 'boobs']).once
|
48
|
+
@sac.parse('@import "subs.css" paper, boobs;')
|
49
|
+
flexmock_verify
|
50
|
+
end
|
51
|
+
|
44
52
|
def test_multi_import
|
45
53
|
flexmock(@sac.document_handler).
|
46
54
|
should_receive(:import_style).ordered.
|
@@ -180,4 +188,54 @@ class ParserTest < Test::Unit::TestCase
|
|
180
188
|
@sac.parse('h1 { color: black !important; }')
|
181
189
|
flexmock_verify
|
182
190
|
end
|
191
|
+
|
192
|
+
def test_pseudo_function
|
193
|
+
flexmock(@sac.document_handler).
|
194
|
+
should_receive(:start_selector).ordered.once
|
195
|
+
flexmock(@sac.document_handler).
|
196
|
+
should_receive(:property).with('color', on { |list|
|
197
|
+
list.length == 1 && list.first.dimension_unit_text.nil? &&
|
198
|
+
list.first.lexical_unit_type == :SAC_IDENT &&
|
199
|
+
list.first.string_value == "black" &&
|
200
|
+
list.first.integer_value.nil?
|
201
|
+
}, true).ordered.once
|
202
|
+
flexmock(@sac.document_handler).
|
203
|
+
should_receive(:end_selector).ordered.once
|
204
|
+
@sac.parse('h1:nth(1) { color: black !important; }')
|
205
|
+
flexmock_verify
|
206
|
+
end
|
207
|
+
|
208
|
+
def test_pseudo_class
|
209
|
+
flexmock(@sac.document_handler).
|
210
|
+
should_receive(:start_selector).ordered.once
|
211
|
+
flexmock(@sac.document_handler).
|
212
|
+
should_receive(:property).with('color', on { |list|
|
213
|
+
list.length == 1 && list.first.dimension_unit_text.nil? &&
|
214
|
+
list.first.lexical_unit_type == :SAC_IDENT &&
|
215
|
+
list.first.string_value == "black" &&
|
216
|
+
list.first.integer_value.nil?
|
217
|
+
}, true).ordered.once
|
218
|
+
flexmock(@sac.document_handler).
|
219
|
+
should_receive(:end_selector).ordered.once
|
220
|
+
@sac.parse('a:hover { color: black !important; }')
|
221
|
+
flexmock_verify
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_pseudo_class_to_css
|
225
|
+
class << @sac.document_handler
|
226
|
+
attr_accessor :selectors
|
227
|
+
alias :start_selector :selectors=
|
228
|
+
end
|
229
|
+
@sac.parse('a:hover { color: black !important; }')
|
230
|
+
assert_equal 'a:hover', @sac.document_handler.selectors.first.to_css
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_pseudo_function_to_css
|
234
|
+
class << @sac.document_handler
|
235
|
+
attr_accessor :selectors
|
236
|
+
alias :start_selector :selectors=
|
237
|
+
end
|
238
|
+
@sac.parse('a:nth(3) { color: black !important; }')
|
239
|
+
assert_equal 'a:nth(3)', @sac.document_handler.selectors.first.to_css
|
240
|
+
end
|
183
241
|
end
|