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.
Files changed (51) hide show
  1. data/.DS_Store +0 -0
  2. data/CHANGELOG.txt +10 -0
  3. data/Manifest.txt +36 -2
  4. data/README.txt +4 -4
  5. data/Rakefile +1 -1
  6. data/lib/css/sac/conditions/attribute_condition.rb +52 -0
  7. data/lib/css/sac/conditions/begin_hyphen_condition.rb +22 -0
  8. data/lib/css/sac/conditions/class_condition.rb +22 -0
  9. data/lib/css/sac/conditions/combinator_condition.rb +36 -0
  10. data/lib/css/sac/conditions/condition.rb +27 -0
  11. data/lib/css/sac/conditions/id_condition.rb +27 -0
  12. data/lib/css/sac/conditions/one_of_condition.rb +22 -0
  13. data/lib/css/sac/conditions/pseudo_class_condition.rb +24 -0
  14. data/lib/css/sac/conditions.rb +5 -0
  15. data/lib/css/sac/document_handler.rb +1 -1
  16. data/lib/css/sac/parser.rb +5 -3
  17. data/lib/css/sac/selectors/child_selector.rb +36 -0
  18. data/lib/css/sac/selectors/conditional_selector.rb +43 -0
  19. data/lib/css/sac/selectors/descendant_selector.rb +36 -0
  20. data/lib/css/sac/selectors/element_selector.rb +35 -0
  21. data/lib/css/sac/selectors/selector.rb +23 -0
  22. data/lib/css/sac/selectors/sibling_selector.rb +35 -0
  23. data/lib/css/sac/selectors/simple_selector.rb +25 -0
  24. data/lib/css/sac/selectors.rb +3 -85
  25. data/lib/css/sac/visitable.rb +104 -0
  26. data/lib/parser.y +24 -15
  27. data/test/condition_test_case.rb +6 -0
  28. data/test/helper.rb +2 -0
  29. data/test/selector_test_case.rb +20 -0
  30. data/test/test_attribute_condition.rb +30 -0
  31. data/test/test_begin_hyphen_condition.rb +15 -0
  32. data/test/test_child_selector.rb +48 -0
  33. data/test/test_class_condition.rb +15 -0
  34. data/test/test_combinator_condition.rb +29 -0
  35. data/test/test_condition.rb +13 -0
  36. data/test/test_conditional_selector.rb +29 -0
  37. data/test/test_descendant_selector.rb +52 -0
  38. data/test/test_element_selector.rb +22 -0
  39. data/test/test_id_condition.rb +16 -0
  40. data/test/test_one_of_condition.rb +15 -0
  41. data/test/test_parser.rb +58 -0
  42. data/test/test_selector.rb +19 -0
  43. data/test/test_selector_as_string.rb +11 -0
  44. data/test/test_selector_parser.rb +2 -2
  45. data/test/test_sibling_selector.rb +33 -0
  46. data/test/test_simple_selector.rb +9 -0
  47. data/test/test_specificity.rb +76 -0
  48. data/test/test_xpath.rb +105 -0
  49. metadata +38 -4
  50. data/lib/css/sac/attribute_condition.rb +0 -78
  51. data/lib/css/sac/condition.rb +0 -21
@@ -1,87 +1,5 @@
1
- module CSS
2
- module SAC
3
- class Selector
4
- attr_reader :selector_type
5
- end
1
+ require "css/sac/selectors/selector"
6
2
 
7
- class SimpleSelector < Selector
8
- def initialize
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
- if val[1] == :SAC_DIRECT_ADJACENT_SELECTOR
145
+ case val[1]
146
+ when :SAC_DIRECT_ADJACENT_SELECTOR
150
147
  SiblingSelector.new(val.first, val[2])
151
- else
152
- DescendantSelector.new(val.first, val[2], val[1])
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 = AttributeCondition.class_condition(val[1]) }
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.attribute_condition(val[2], val[4])
165
+ result = AttributeCondition.build(val[2], val[4])
167
166
  }
168
167
  ;
169
168
  pseudo
170
- : ':' FUNCTION s_0toN IDENT s_0toN ')'
171
- | ':' FUNCTION s_0toN s_0toN ')'
172
- | ':' IDENT { result = AttributeCondition.pseudo_class_condition(val[1]) }
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 { result = [val[0], val[2], val[3]] }
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 = AttributeCondition.attribute_id(val.first) }
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
@@ -0,0 +1,6 @@
1
+ class ConditionTestCase < Test::Unit::TestCase
2
+ include CSS::SAC::Conditions
3
+
4
+ Node = Struct.new(:name, :parent, :child, :next_sibling, :attributes)
5
+ undef :default_test
6
+ end
data/test/helper.rb CHANGED
@@ -5,3 +5,5 @@ require "flexmock"
5
5
  require "flexmock/test_unit"
6
6
 
7
7
  require "css/sac"
8
+ require "test/selector_test_case"
9
+ require "test/condition_test_case"
@@ -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