csspool 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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