csspool-st 3.1.0

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 (64) hide show
  1. data/.autotest +16 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.rdoc +87 -0
  4. data/Manifest.txt +62 -0
  5. data/README.rdoc +65 -0
  6. data/Rakefile +50 -0
  7. data/lib/csspool/collection.rb +50 -0
  8. data/lib/csspool/css/charset.rb +13 -0
  9. data/lib/csspool/css/declaration.rb +19 -0
  10. data/lib/csspool/css/document.rb +34 -0
  11. data/lib/csspool/css/document_handler.rb +51 -0
  12. data/lib/csspool/css/import_rule.rb +27 -0
  13. data/lib/csspool/css/media.rb +13 -0
  14. data/lib/csspool/css/parser.rb +1298 -0
  15. data/lib/csspool/css/parser.y +398 -0
  16. data/lib/csspool/css/rule_set.rb +17 -0
  17. data/lib/csspool/css/tokenizer.rb +231 -0
  18. data/lib/csspool/css/tokenizer.rex +97 -0
  19. data/lib/csspool/css.rb +8 -0
  20. data/lib/csspool/node.rb +41 -0
  21. data/lib/csspool/sac/document.rb +35 -0
  22. data/lib/csspool/sac/parser.rb +16 -0
  23. data/lib/csspool/sac.rb +2 -0
  24. data/lib/csspool/selector.rb +36 -0
  25. data/lib/csspool/selectors/additional.rb +6 -0
  26. data/lib/csspool/selectors/attribute.rb +21 -0
  27. data/lib/csspool/selectors/class.rb +11 -0
  28. data/lib/csspool/selectors/id.rb +11 -0
  29. data/lib/csspool/selectors/pseudo_class.rb +13 -0
  30. data/lib/csspool/selectors/simple.rb +22 -0
  31. data/lib/csspool/selectors/type.rb +6 -0
  32. data/lib/csspool/selectors/universal.rb +6 -0
  33. data/lib/csspool/selectors.rb +9 -0
  34. data/lib/csspool/terms/function.rb +17 -0
  35. data/lib/csspool/terms/hash.rb +6 -0
  36. data/lib/csspool/terms/ident.rb +15 -0
  37. data/lib/csspool/terms/number.rb +14 -0
  38. data/lib/csspool/terms/rgb.rb +20 -0
  39. data/lib/csspool/terms/string.rb +6 -0
  40. data/lib/csspool/terms/uri.rb +6 -0
  41. data/lib/csspool/terms.rb +7 -0
  42. data/lib/csspool/visitors/children.rb +50 -0
  43. data/lib/csspool/visitors/comparable.rb +84 -0
  44. data/lib/csspool/visitors/iterator.rb +80 -0
  45. data/lib/csspool/visitors/to_css.rb +248 -0
  46. data/lib/csspool/visitors/visitor.rb +17 -0
  47. data/lib/csspool/visitors.rb +5 -0
  48. data/lib/csspool.rb +21 -0
  49. data/test/css/test_document.rb +13 -0
  50. data/test/css/test_import_rule.rb +42 -0
  51. data/test/css/test_parser.rb +462 -0
  52. data/test/css/test_tokenizer.rb +320 -0
  53. data/test/helper.rb +65 -0
  54. data/test/sac/test_parser.rb +123 -0
  55. data/test/sac/test_properties.rb +43 -0
  56. data/test/sac/test_terms.rb +228 -0
  57. data/test/test_collection.rb +81 -0
  58. data/test/test_parser.rb +91 -0
  59. data/test/test_selector.rb +51 -0
  60. data/test/visitors/test_children.rb +20 -0
  61. data/test/visitors/test_comparable.rb +102 -0
  62. data/test/visitors/test_each.rb +19 -0
  63. data/test/visitors/test_to_css.rb +309 -0
  64. metadata +214 -0
@@ -0,0 +1,228 @@
1
+ # encoding: utf-8
2
+ require 'helper'
3
+
4
+ module CSSPool
5
+ module SAC
6
+ class TestTerms < CSSPool::TestCase
7
+ def setup
8
+ @doc = MyDoc.new
9
+ @parser = CSSPool::SAC::Parser.new(@doc)
10
+ end
11
+
12
+ def test_hash_range
13
+ @parser.parse <<-eocss
14
+ div { border: #123; }
15
+ eocss
16
+ hash = @doc.properties.first[1].first
17
+ assert_equal '123', hash.value
18
+ end
19
+
20
+ def test_rgb
21
+ @parser.parse <<-eocss
22
+ div { border: rgb(1,2,3); }
23
+ eocss
24
+ color = @doc.properties.first[1].first
25
+ assert_equal 1, color.red.value
26
+ assert_equal 2, color.green.value
27
+ assert_equal 3, color.blue.value
28
+ assert_match('rgb(1, 2, 3)', color.to_css)
29
+ end
30
+
31
+ def test_rgb_with_percentage
32
+ @parser.parse <<-eocss
33
+ div { border: rgb(100%, 2%, 3%); }
34
+ eocss
35
+ color = @doc.properties.first[1].first
36
+ assert_equal 100, color.red.value
37
+ assert_equal 2, color.green.value
38
+ assert_equal 3, color.blue.value
39
+ assert_match('rgb(100%, 2%, 3%)', color.to_css)
40
+ end
41
+
42
+ def test_negative_number
43
+ @parser.parse <<-eocss
44
+ div { border: -1px; }
45
+ eocss
46
+ assert_equal 1, @doc.properties.length
47
+ size = @doc.properties.first[1].first
48
+ assert_equal :minus, size.unary_operator
49
+ assert_equal 1, size.value
50
+ assert_equal '-1px', size.to_s
51
+ assert_equal '-1px', size.to_css
52
+ end
53
+
54
+ def test_positive_number
55
+ @parser.parse <<-eocss
56
+ div { border: 1px; }
57
+ eocss
58
+ assert_equal 1, @doc.properties.length
59
+ size = @doc.properties.first[1].first
60
+ assert_equal 1, size.value
61
+ assert_equal '1px', size.to_s
62
+ end
63
+
64
+ %w{
65
+ 1 1em 1ex 1px 1in 1cm 1mm 1pt 1pc 1% 1deg 1rad 1ms 1s 1Hz 1kHz
66
+ }.each do |num|
67
+ define_method(:"test_num_#{num}") do
68
+ @parser.parse <<-eocss
69
+ div { border: #{num}; }
70
+ eocss
71
+ assert_equal 1, @doc.properties.length
72
+ size = @doc.properties.first[1].first
73
+ assert_equal 1, size.value
74
+ assert_equal num, size.to_s
75
+ assert_equal num, size.to_css
76
+ end
77
+ end
78
+
79
+ def test_selector_attribute
80
+ @parser.parse <<-eocss
81
+ div[attr = value] { }
82
+ div[attr\\== value] { }
83
+ div[attr="\\"quotes\\""] { }
84
+ div[attr = unicode\\ \\1D11E\\BF ] { }
85
+ eocss
86
+
87
+ attrs = @doc.end_selectors.flatten.map(&:simple_selectors).flatten.map(&:additional_selectors).flatten
88
+ assert_equal 4, attrs.length
89
+
90
+ attrs.shift.tap do |attr|
91
+ assert_equal "attr", attr.name,
92
+ "Interprets name."
93
+ assert_equal "value", attr.value,
94
+ "Interprets bare value."
95
+ end
96
+
97
+ assert_equal "attr=", attrs.shift.name,
98
+ "Interprets identifier escapes."
99
+
100
+ assert_equal "\"quotes\"", attrs.shift.value,
101
+ "Interprets quoted values."
102
+
103
+ assert_equal "unicode \360\235\204\236\302\277", attrs.shift.value,
104
+ "Interprets unicode escapes."
105
+ end
106
+
107
+ def test_string_term
108
+ @parser.parse <<-eocss
109
+ div { content: "basic"; }
110
+ div { content: "\\"quotes\\""; }
111
+ div { content: "unicode \\1D11E\\BF "; }
112
+ div { content: "contin\\\nuation"; }
113
+ div { content: "new\\aline"; }
114
+ div { content: "\\11FFFF "; }
115
+ eocss
116
+ terms = @doc.properties.map {|s| s[1].first}
117
+ assert_equal 6, terms.length
118
+
119
+ assert_equal 'basic', terms.shift.value,
120
+ "Recognizes a basic string"
121
+
122
+ assert_equal "\"quotes\"", terms.shift.value,
123
+ "Recognizes strings containing quotes."
124
+
125
+ assert_equal "unicode \360\235\204\236\302\277", terms.shift.value,
126
+ "Interprets unicode escapes."
127
+
128
+ assert_equal "continuation", terms.shift.value,
129
+ "Supports line continuation."
130
+
131
+ assert_equal "new\nline", terms.shift.value,
132
+ "Interprets newline escape."
133
+
134
+ assert_equal "\357\277\275", terms.shift.value,
135
+ "Kills absurd characters."
136
+ end
137
+
138
+ def test_inherit
139
+ @parser.parse <<-eocss
140
+ div { color: inherit; }
141
+ eocss
142
+ assert_equal 1, @doc.properties.length
143
+ string = @doc.properties.first[1].first
144
+ assert_equal 'inherit', string.value
145
+ assert_equal 'inherit', string.to_css
146
+ end
147
+
148
+ def test_important
149
+ @parser.parse <<-eocss
150
+ div { color: inherit !important; }
151
+ eocss
152
+ assert_equal 1, @doc.properties.length
153
+ string = @doc.properties.first[1].first
154
+ assert_equal 'inherit', string.value
155
+ assert_equal 'inherit', string.to_css
156
+ end
157
+
158
+ def test_declaration
159
+ @parser.parse <<-eocss
160
+ div { property: value; }
161
+ div { colon\\:: value; }
162
+ div { space\\ : value; }
163
+ eocss
164
+ properties = @doc.properties.map {|s| s[0]}
165
+ assert_equal 3, properties.length
166
+
167
+ assert_equal 'property', properties.shift,
168
+ "Recognizes basic function."
169
+
170
+ assert_equal 'colon:', properties.shift,
171
+ "Recognizes property with escaped COLON."
172
+
173
+ assert_equal 'space ', properties.shift,
174
+ "Recognizes property with escaped SPACE."
175
+ end
176
+
177
+ def test_function
178
+ @parser.parse <<-eocss
179
+ div { content: attr(\"value\", ident); }
180
+ div { content: \\30(\"value\", ident); }
181
+ div { content: a\\ function(\"value\", ident); }
182
+ div { content: a\\((\"value\", ident); }
183
+ eocss
184
+ terms = @doc.properties.map {|s| s[1].first}
185
+ assert_equal 4, terms.length
186
+
187
+ assert_equal 'attr', terms.shift.name,
188
+ "Recognizes basic function."
189
+
190
+ assert_equal '0', terms.shift.name,
191
+ "Recognizes numeric function."
192
+
193
+ assert_equal 'a function', terms.shift.name,
194
+ "Recognizes function with escaped SPACE."
195
+
196
+ assert_equal 'a(', terms.shift.name,
197
+ "Recognizes function with escaped LPAREN."
198
+ end
199
+
200
+ def test_uri
201
+ @parser.parse <<-eocss
202
+ div { background: url(http://example.com/); }
203
+ div { background: url( http://example.com/ ); }
204
+ div { background: url("http://example.com/"); }
205
+ div { background: url( " http://example.com/ " ); }
206
+ div { background: url(http://example.com/\\"); }
207
+ eocss
208
+ terms = @doc.properties.map {|s| s[1].first}
209
+ assert_equal 5, terms.length
210
+
211
+ assert_equal 'http://example.com/', terms.shift.value,
212
+ "Recognizes bare URI."
213
+
214
+ assert_equal 'http://example.com/', terms.shift.value,
215
+ "Recognize URI with spaces"
216
+
217
+ assert_equal 'http://example.com/', terms.shift.value,
218
+ "Recognize quoted URI"
219
+
220
+ assert_equal ' http://example.com/ ', terms.shift.value,
221
+ "Recognize quoted URI"
222
+
223
+ assert_equal 'http://example.com/"', terms.shift.value,
224
+ "Recognizes bare URI with quotes"
225
+ end
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,81 @@
1
+ require 'helper'
2
+
3
+ module CSSPool
4
+ class TestCollection < CSSPool::TestCase
5
+ def test_new
6
+ assert CSSPool::Collection.new
7
+ assert CSSPool::Collection.new { |url| }
8
+ end
9
+
10
+ def test_append
11
+ collection = CSSPool::Collection.new
12
+ collection << "div { background: green; }"
13
+ assert_equal 1, collection.length
14
+ end
15
+
16
+ def test_collection_imports_stuff
17
+ called = false
18
+ collection = CSSPool::Collection.new do |url|
19
+ called = true
20
+ assert_equal 'hello.css', url
21
+ "div { background: red; }"
22
+ end
23
+
24
+ collection << '@import url(hello.css);'
25
+ assert called, "block was not called"
26
+ assert_equal 2, collection.length
27
+ end
28
+
29
+ def test_collection_imports_imports_imports
30
+ css = {
31
+ 'foo.css' => '@import url("bar.css");',
32
+ 'bar.css' => '@import url("baz.css");',
33
+ 'baz.css' => 'div { background: red; }',
34
+ }
35
+
36
+ collection = CSSPool::Collection.new do |url|
37
+ css[url] || raise
38
+ end
39
+
40
+ collection << '@import url(foo.css);'
41
+ assert_equal 4, collection.length
42
+ assert_nil collection.last.parent
43
+ assert_equal collection[-2].parent, collection.last
44
+ assert_equal collection[-3].parent, collection[-2]
45
+ assert_equal collection[-4].parent, collection[-3]
46
+ end
47
+
48
+ def test_load_only_once
49
+ css = {
50
+ 'foo.css' => '@import url("foo.css");',
51
+ }
52
+
53
+ collection = CSSPool::Collection.new do |url|
54
+ css[url] || raise
55
+ end
56
+
57
+ collection << '@import url(foo.css);'
58
+
59
+ assert_equal 2, collection.length
60
+ end
61
+
62
+ def test_each
63
+ css = {
64
+ 'foo.css' => '@import url("foo.css");',
65
+ }
66
+
67
+ collection = CSSPool::Collection.new do |url|
68
+ css[url] || raise(url.inspect)
69
+ end
70
+
71
+ collection << '@import url(foo.css);'
72
+
73
+ list = []
74
+ collection.each do |thing|
75
+ list << thing
76
+ end
77
+
78
+ assert_equal 2, list.length
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,91 @@
1
+ require 'helper'
2
+
3
+ module CSSPool
4
+ class TestParser < CSSPool::TestCase
5
+ def test_empty_doc_on_blank
6
+ assert CSSPool.CSS(nil)
7
+ assert CSSPool.CSS('')
8
+ end
9
+
10
+ def test_doc_charset
11
+ doc = CSSPool.CSS <<-eocss
12
+ @charset "UTF-8";
13
+ @import url("foo.css") screen;
14
+ div#a, a.foo, a:hover, a[href][int="10"]{ background: red; }
15
+ eocss
16
+ assert_equal 'UTF-8', doc.charsets.first.name
17
+ end
18
+
19
+ def test_doc_parser
20
+ doc = CSSPool.CSS <<-eocss
21
+ @charset "UTF-8";
22
+ div#a, a.foo, a:hover, a[href][int="10"]{ background: red; }
23
+ eocss
24
+
25
+ assert_equal 1, doc.rule_sets.length
26
+ rule_set = doc.rule_sets.first
27
+ assert_equal 4, rule_set.selectors.length
28
+ assert_equal 1, rule_set.declarations.length
29
+ assert_equal 'background', rule_set.declarations.first.property
30
+ end
31
+
32
+ def test_media
33
+ doc = CSSPool.CSS <<-eocss
34
+ @media print {
35
+ div { background: red, blue; }
36
+ }
37
+ eocss
38
+ assert_equal 1, doc.rule_sets.first.media.length
39
+ end
40
+
41
+ def test_universal_to_css
42
+ doc = CSSPool.CSS <<-eocss
43
+ * { background: red, blue; }
44
+ eocss
45
+ assert_match '*', doc.to_css
46
+ end
47
+
48
+ def test_doc_to_css
49
+ doc = CSSPool.CSS <<-eocss
50
+ div#a, a.foo, a:hover, a[href][int="10"]{ background: red, blue; }
51
+ eocss
52
+ assert_match 'div#a, a.foo, a:hover, a[href][int="10"]', doc.to_css
53
+ assert_match 'background: red, blue;', doc.to_css
54
+ end
55
+
56
+ def test_doc_desc_to_css
57
+ doc = CSSPool.CSS <<-eocss
58
+ div > a { background: #123; }
59
+ eocss
60
+ assert_match 'div > a', doc.to_css
61
+ end
62
+
63
+ def test_doc_pseudo_to_css
64
+ doc = CSSPool.CSS <<-eocss
65
+ :hover { background: #123; }
66
+ eocss
67
+ assert_match ':hover', doc.to_css
68
+ end
69
+
70
+ def test_doc_id_to_css
71
+ doc = CSSPool.CSS <<-eocss
72
+ #hover { background: #123; }
73
+ eocss
74
+ assert_match '#hover', doc.to_css
75
+ end
76
+
77
+ def test_important
78
+ doc = CSSPool.CSS <<-eocss
79
+ div > a { background: #123 !important; }
80
+ eocss
81
+ assert_match '!important', doc.to_css
82
+ end
83
+
84
+ def test_doc_func_to_css
85
+ doc = CSSPool.CSS <<-eocss
86
+ div { border: foo(1, 2); }
87
+ eocss
88
+ assert_match('foo(1, 2)', doc.to_css)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,51 @@
1
+ require 'helper'
2
+
3
+ module CSSPool
4
+ class TestSelector < CSSPool::TestCase
5
+ def test_specificity
6
+ doc = CSSPool.CSS <<-eocss
7
+ *, foo > bar, #hover, :hover, div#a, a.foo, a:hover, a[href][int="10"], :before, ::before { background: red; }
8
+ eocss
9
+ selectors = doc.rule_sets.first.selectors
10
+ specs = selectors.map do |sel|
11
+ sel.specificity
12
+ end
13
+ assert_equal [
14
+ [0, 0, 1],
15
+ [0, 0, 2],
16
+ [1, 0, 0],
17
+ [0, 1, 0],
18
+ [1, 0, 1],
19
+ [0, 1, 1],
20
+ [0, 1, 1],
21
+ [0, 2, 1],
22
+ [0, 0, 1],
23
+ [0, 0, 1]
24
+ ], specs
25
+ end
26
+
27
+ def test_selector_knows_its_ruleset
28
+ doc = CSSPool.CSS <<-eocss
29
+ a[href][int="10"]{ background: red; }
30
+ eocss
31
+ rs = doc.rule_sets.first
32
+ assert_equal rs, rs.selectors.first.rule_set
33
+ end
34
+
35
+ def test_selector_gets_declarations
36
+ doc = CSSPool.CSS <<-eocss
37
+ a[href][int="10"]{ background: red; }
38
+ eocss
39
+ rs = doc.rule_sets.first
40
+ assert_equal rs.declarations, rs.selectors.first.declarations
41
+ end
42
+
43
+ def test_declaration_should_know_ruleset
44
+ doc = CSSPool.CSS <<-eocss
45
+ a[href][int="10"]{ background: red; }
46
+ eocss
47
+ rs = doc.rule_sets.first
48
+ rs.declarations.each { |del| assert_equal rs, del.rule_set }
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,20 @@
1
+ require 'helper'
2
+
3
+ module CSSPool
4
+ module Visitors
5
+ class TestChildren < CSSPool::TestCase
6
+ def test_iterate
7
+ doc = CSSPool.CSS <<-eocss
8
+ @charset "UTF-8";
9
+ @import url("foo.css") screen;
10
+ div#a, a.foo, a:hover, a[href][int="10"]{ background: red; }
11
+ eocss
12
+
13
+ stack = [doc]
14
+ until stack.empty? do
15
+ stack += stack.pop.children
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,102 @@
1
+ require 'helper'
2
+
3
+ module CSSPool
4
+ module Visitors
5
+ class TestComparable < CSSPool::TestCase
6
+ def equalitest css
7
+ doc1 = CSSPool.CSS css
8
+ doc2 = CSSPool.CSS css
9
+ assert_equal doc1, doc2
10
+
11
+ list1 = []
12
+ list2 = []
13
+
14
+ doc1.each { |node| list1 << node }
15
+ doc2.each { |node| list2 << node }
16
+
17
+ assert_equal list1, list2
18
+
19
+ stack = [doc1]
20
+ until stack.empty? do
21
+ stack += stack.pop.children
22
+ end
23
+
24
+ assert_equal doc1.hash, doc2.hash
25
+ end
26
+
27
+ def test_not_equal
28
+ doc1 = CSSPool.CSS 'div { border: foo(1, 2); }'
29
+ assert_not_equal nil, doc1
30
+ end
31
+
32
+ def test_hash_range
33
+ equalitest 'div { border: #123; }'
34
+ end
35
+
36
+ def test_div_with_id
37
+ equalitest 'div#foo { border: #123; }'
38
+ end
39
+
40
+ def test_div_with_pseudo
41
+ equalitest 'div:foo { border: #123; }'
42
+ end
43
+
44
+ def test_div_with_universal
45
+ equalitest '* { border: #123; }'
46
+ end
47
+
48
+ def test_simple
49
+ equalitest '.foo { border: #123; }'
50
+ end
51
+
52
+ def test_rgb
53
+ equalitest 'div { border: rgb(1,2,3); }'
54
+ end
55
+
56
+ def test_rgb_with_percentage
57
+ equalitest 'div { border: rgb(100%,2%,3%); }'
58
+ end
59
+
60
+ def test_negative_number
61
+ equalitest 'div { border: -1px; }'
62
+ end
63
+
64
+ def test_positive_number
65
+ equalitest 'div { border: 1px; }'
66
+ end
67
+
68
+ %w{
69
+ 1 1em 1ex 1px 1in 1cm 1mm 1pt 1pc 1% 1deg 1rad 1ms 1s 1Hz 1kHz
70
+ }.each do |num|
71
+ define_method(:"test_num_#{num}") do
72
+ equalitest "div { border: #{num}; }"
73
+ end
74
+ end
75
+
76
+ def test_string_term
77
+ equalitest 'div { border: "hello"; }'
78
+ end
79
+
80
+ def test_inherit
81
+ equalitest 'div { color: inherit; }'
82
+ end
83
+
84
+ def test_important
85
+ equalitest 'div { color: inherit !important; }'
86
+ end
87
+
88
+ def test_function
89
+ equalitest 'div { border: foo("hello"); }'
90
+ end
91
+
92
+ def test_uri
93
+ equalitest 'div { border: url(http://tenderlovemaking.com/); }'
94
+ end
95
+
96
+ def test_import
97
+ equalitest '@import "foo.css" screen, print;'
98
+ equalitest '@import "foo.css";'
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,19 @@
1
+ require 'helper'
2
+
3
+ module CSSPool
4
+ module Visitors
5
+ class TestEach < CSSPool::TestCase
6
+ def test_iterate
7
+ doc = CSSPool.CSS <<-eocss
8
+ @charset "UTF-8";
9
+ @import url("foo.css") screen;
10
+ div#a, a.foo, a:hover, a[href][int="10"]{ background: red; }
11
+ eocss
12
+ list = []
13
+ doc.each { |node| list << node }
14
+ assert_equal 20, list.length
15
+ assert list.hash
16
+ end
17
+ end
18
+ end
19
+ end