csspool 2.0.0 → 3.0.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.
- data/.gemtest +0 -0
- data/CHANGELOG.rdoc +6 -0
- data/Manifest.txt +10 -14
- data/README.rdoc +8 -21
- data/Rakefile +36 -2
- data/lib/csspool/collection.rb +2 -2
- data/lib/csspool/css/charset.rb +8 -2
- data/lib/csspool/css/declaration.rb +13 -2
- data/lib/csspool/css/document_handler.rb +3 -3
- data/lib/csspool/css/import_rule.rb +15 -3
- data/lib/csspool/css/media.rb +8 -2
- data/lib/csspool/css/parser.rb +1090 -0
- data/lib/csspool/css/parser.y +347 -0
- data/lib/csspool/css/rule_set.rb +8 -3
- data/lib/csspool/css/tokenizer.rb +228 -0
- data/lib/csspool/css/tokenizer.rex +96 -0
- data/lib/csspool/css.rb +1 -0
- data/lib/csspool/node.rb +29 -1
- data/lib/csspool/sac/document.rb +3 -3
- data/lib/csspool/sac/parser.rb +6 -112
- data/lib/csspool/terms/function.rb +1 -1
- data/lib/csspool/terms/ident.rb +1 -1
- data/lib/csspool/terms/number.rb +1 -1
- data/lib/csspool/terms/rgb.rb +1 -4
- data/lib/csspool/terms/string.rb +1 -1
- data/lib/csspool/visitors/children.rb +50 -0
- data/lib/csspool/visitors/comparable.rb +9 -3
- data/lib/csspool/visitors/iterator.rb +80 -0
- data/lib/csspool/visitors/to_css.rb +61 -45
- data/lib/csspool/visitors.rb +2 -0
- data/lib/csspool.rb +6 -3
- data/test/css/test_parser.rb +412 -0
- data/test/css/test_tokenizer.rb +320 -0
- data/test/helper.rb +2 -2
- data/test/sac/test_parser.rb +3 -8
- data/test/sac/test_terms.rb +128 -34
- data/test/test_collection.rb +1 -1
- data/test/test_parser.rb +1 -1
- data/test/visitors/test_children.rb +20 -0
- data/test/visitors/test_comparable.rb +31 -1
- data/test/visitors/test_each.rb +19 -0
- data/test/visitors/test_to_css.rb +125 -1
- metadata +90 -68
- data/lib/csspool/lib_croco/cr_additional_sel.rb +0 -46
- data/lib/csspool/lib_croco/cr_attr_sel.rb +0 -16
- data/lib/csspool/lib_croco/cr_doc_handler.rb +0 -24
- data/lib/csspool/lib_croco/cr_num.rb +0 -13
- data/lib/csspool/lib_croco/cr_parser.rb +0 -11
- data/lib/csspool/lib_croco/cr_parsing_location.rb +0 -17
- data/lib/csspool/lib_croco/cr_pseudo.rb +0 -14
- data/lib/csspool/lib_croco/cr_rgb.rb +0 -18
- data/lib/csspool/lib_croco/cr_selector.rb +0 -34
- data/lib/csspool/lib_croco/cr_simple_sel.rb +0 -54
- data/lib/csspool/lib_croco/cr_term.rb +0 -97
- data/lib/csspool/lib_croco/glist.rb +0 -21
- data/lib/csspool/lib_croco.rb +0 -78
- data/lib/csspool/visitable.rb +0 -18
@@ -0,0 +1,320 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require "helper"
|
4
|
+
|
5
|
+
module CSSPool
|
6
|
+
module CSS
|
7
|
+
class TestTokenizer < CSSPool::TestCase
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
@scanner = Class.new(CSSPool::CSS::Tokenizer) {
|
11
|
+
def do_parse
|
12
|
+
end
|
13
|
+
}.new
|
14
|
+
end
|
15
|
+
|
16
|
+
{
|
17
|
+
'em' => :EMS,
|
18
|
+
'ex' => :EXS,
|
19
|
+
'px' => :LENGTH,
|
20
|
+
'cm' => :LENGTH,
|
21
|
+
'mm' => :LENGTH,
|
22
|
+
'in' => :LENGTH,
|
23
|
+
'pt' => :LENGTH,
|
24
|
+
'pc' => :LENGTH,
|
25
|
+
'deg' => :ANGLE,
|
26
|
+
'rad' => :ANGLE,
|
27
|
+
'grad' => :ANGLE,
|
28
|
+
'ms' => :TIME,
|
29
|
+
's' => :TIME,
|
30
|
+
'hz' => :FREQ,
|
31
|
+
'khz' => :FREQ,
|
32
|
+
'%' => :PERCENTAGE,
|
33
|
+
}.each do |unit,sym|
|
34
|
+
define_method :"test_#{unit}" do
|
35
|
+
['10', '0.1'].each do |num|
|
36
|
+
num = "#{num}#{unit}"
|
37
|
+
[num, " #{num}", "#{num} ", " #{num} "].each do |str|
|
38
|
+
@scanner.scan str
|
39
|
+
assert_tokens([[sym, str]], @scanner)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_num
|
46
|
+
['10', '0.1'].each do |num|
|
47
|
+
[num, " #{num}", "#{num} ", " #{num} "].each do |str|
|
48
|
+
@scanner.scan str
|
49
|
+
assert_tokens([[:NUMBER, str]], @scanner)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_important
|
55
|
+
[
|
56
|
+
'!important',
|
57
|
+
' !important',
|
58
|
+
'!important ',
|
59
|
+
'! important ',
|
60
|
+
' ! important ',
|
61
|
+
].each do |str|
|
62
|
+
@scanner.scan str
|
63
|
+
assert_tokens([[:IMPORTANT_SYM, str]], @scanner)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
{
|
68
|
+
'@page' => :PAGE_SYM,
|
69
|
+
'@import' => :IMPORT_SYM,
|
70
|
+
'@media' => :MEDIA_SYM,
|
71
|
+
'@charset' => :CHARSET_SYM,
|
72
|
+
}.each do |k,v|
|
73
|
+
define_method(:"test_#{k.sub(/@/, '')}") do
|
74
|
+
[k, " #{k}", "#{k} ", " #{k} "].each do |str|
|
75
|
+
@scanner.scan str
|
76
|
+
assert_tokens([[v, str]], @scanner)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_invalid
|
82
|
+
str = "'internet"
|
83
|
+
@scanner.scan str
|
84
|
+
assert_tokens([[:INVALID, str]], @scanner)
|
85
|
+
|
86
|
+
str = '"internet'
|
87
|
+
@scanner.scan str
|
88
|
+
assert_tokens([[:INVALID, str]], @scanner)
|
89
|
+
end
|
90
|
+
|
91
|
+
#def test_comment
|
92
|
+
# str = "/**** Hello World ***/"
|
93
|
+
# @scanner.scan str
|
94
|
+
# assert_tokens([[:COMMENT, str]], @scanner)
|
95
|
+
|
96
|
+
# str = "/* Hello World */"
|
97
|
+
# @scanner.scan str
|
98
|
+
# assert_tokens([[:COMMENT, str]], @scanner)
|
99
|
+
#end
|
100
|
+
|
101
|
+
def test_rbrace
|
102
|
+
str = " } \n "
|
103
|
+
@scanner.scan str
|
104
|
+
assert_tokens([[:RBRACE, str]], @scanner)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_lbrace
|
108
|
+
str = " { "
|
109
|
+
@scanner.scan str
|
110
|
+
assert_tokens([[:LBRACE, str]], @scanner)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_semi
|
114
|
+
str = " ; "
|
115
|
+
@scanner.scan str
|
116
|
+
assert_tokens([[:SEMI, ';']], @scanner)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_cdc
|
120
|
+
@scanner.scan("-->")
|
121
|
+
assert_tokens([[:CDC, "-->"]], @scanner)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_cdo
|
125
|
+
@scanner.scan("<!--")
|
126
|
+
assert_tokens([[:CDO, "<!--"]], @scanner)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_unicode_range
|
130
|
+
@scanner.scan("U+0-10FFFF")
|
131
|
+
assert_tokens([[:UNICODE_RANGE, "U+0-10FFFF"]], @scanner)
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_url_with_string
|
135
|
+
@scanner.scan("url('http://tlm.com')")
|
136
|
+
assert_tokens([[:URI, "url('http://tlm.com')"]], @scanner)
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_url_with_others
|
140
|
+
@scanner.scan("url(http://tlm.com?f&b)")
|
141
|
+
assert_tokens([[:URI, "url(http://tlm.com?f&b)"]], @scanner)
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_unicode
|
145
|
+
@scanner.scan("a日本語")
|
146
|
+
assert_tokens([[:IDENT, 'a日本語']], @scanner)
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_tokenize_bad_percent
|
150
|
+
@scanner.scan("%")
|
151
|
+
assert_tokens([["%", "%"]], @scanner)
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_not_equal
|
155
|
+
@scanner.scan("h1[a!='Tender Lovemaking']")
|
156
|
+
assert_tokens([ [:IDENT, 'h1'],
|
157
|
+
[:LSQUARE, '['],
|
158
|
+
[:IDENT, 'a'],
|
159
|
+
[:NOT_EQUAL, '!='],
|
160
|
+
[:STRING, "'Tender Lovemaking'"],
|
161
|
+
[:RSQUARE, ']'],
|
162
|
+
], @scanner)
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_negation
|
166
|
+
@scanner.scan("p:not(.a)")
|
167
|
+
assert_tokens([ [:IDENT, 'p'],
|
168
|
+
[:NOT, ':not('],
|
169
|
+
['.', '.'],
|
170
|
+
[:IDENT, 'a'],
|
171
|
+
[:RPAREN, ')'],
|
172
|
+
], @scanner)
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_function
|
176
|
+
@scanner.scan("script comment()")
|
177
|
+
assert_tokens([ [:IDENT, 'script'],
|
178
|
+
[:S, ' '],
|
179
|
+
[:FUNCTION, 'comment('],
|
180
|
+
[:RPAREN, ')'],
|
181
|
+
], @scanner)
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_preceding_selector
|
185
|
+
@scanner.scan("E ~ F")
|
186
|
+
assert_tokens([ [:IDENT, 'E'],
|
187
|
+
[:TILDE, ' ~ '],
|
188
|
+
[:IDENT, 'F'],
|
189
|
+
], @scanner)
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_scan_attribute_string
|
193
|
+
@scanner.scan("h1[a='Tender Lovemaking']")
|
194
|
+
assert_tokens([ [:IDENT, 'h1'],
|
195
|
+
[:LSQUARE, '['],
|
196
|
+
[:IDENT, 'a'],
|
197
|
+
[:EQUAL, '='],
|
198
|
+
[:STRING, "'Tender Lovemaking'"],
|
199
|
+
[:RSQUARE, ']'],
|
200
|
+
], @scanner)
|
201
|
+
@scanner.scan('h1[a="Tender Lovemaking"]')
|
202
|
+
assert_tokens([ [:IDENT, 'h1'],
|
203
|
+
[:LSQUARE, '['],
|
204
|
+
[:IDENT, 'a'],
|
205
|
+
[:EQUAL, '='],
|
206
|
+
[:STRING, '"Tender Lovemaking"'],
|
207
|
+
[:RSQUARE, ']'],
|
208
|
+
], @scanner)
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_scan_id
|
212
|
+
@scanner.scan('#foo')
|
213
|
+
assert_tokens([ [:HASH, '#foo'] ], @scanner)
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_scan_pseudo
|
217
|
+
@scanner.scan('a:visited')
|
218
|
+
assert_tokens([ [:IDENT, 'a'],
|
219
|
+
[':', ':'],
|
220
|
+
[:IDENT, 'visited']
|
221
|
+
], @scanner)
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_scan_star
|
225
|
+
@scanner.scan('*')
|
226
|
+
assert_tokens([ [:STAR, '*'], ], @scanner)
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_ident_with_minus
|
230
|
+
@scanner.scan('-book')
|
231
|
+
assert_tokens([ [:IDENT, '-book'], ], @scanner)
|
232
|
+
end
|
233
|
+
|
234
|
+
def test_scan_class
|
235
|
+
@scanner.scan('x.awesome')
|
236
|
+
assert_tokens([ [:IDENT, 'x'],
|
237
|
+
['.', '.'],
|
238
|
+
[:IDENT, 'awesome'],
|
239
|
+
], @scanner)
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_scan_greater
|
243
|
+
@scanner.scan('x > y')
|
244
|
+
assert_tokens([ [:IDENT, 'x'],
|
245
|
+
[:GREATER, ' > '],
|
246
|
+
[:IDENT, 'y']
|
247
|
+
], @scanner)
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_scan_slash
|
251
|
+
@scanner.scan('x/y')
|
252
|
+
assert_tokens([ [:IDENT, 'x'],
|
253
|
+
[:SLASH, '/'],
|
254
|
+
[:IDENT, 'y']
|
255
|
+
], @scanner)
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_scan_doubleslash
|
259
|
+
@scanner.scan('x//y')
|
260
|
+
assert_tokens([ [:IDENT, 'x'],
|
261
|
+
[:DOUBLESLASH, '//'],
|
262
|
+
[:IDENT, 'y']
|
263
|
+
], @scanner)
|
264
|
+
end
|
265
|
+
|
266
|
+
def test_scan_function_selector
|
267
|
+
@scanner.scan('x:eq(0)')
|
268
|
+
assert_tokens([ [:IDENT, 'x'],
|
269
|
+
[':', ':'],
|
270
|
+
[:FUNCTION, 'eq('],
|
271
|
+
[:NUMBER, "0"],
|
272
|
+
[:RPAREN, ')'],
|
273
|
+
], @scanner)
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_scan_an_plus_b
|
277
|
+
@scanner.scan('x:nth-child(5n+3)')
|
278
|
+
assert_tokens([ [:IDENT, 'x'],
|
279
|
+
[':', ':'],
|
280
|
+
[:FUNCTION, 'nth-child('],
|
281
|
+
[:NUMBER, '5'],
|
282
|
+
[:IDENT, 'n'],
|
283
|
+
[:PLUS, '+'],
|
284
|
+
[:NUMBER, '3'],
|
285
|
+
[:RPAREN, ')'],
|
286
|
+
], @scanner)
|
287
|
+
|
288
|
+
@scanner.scan('x:nth-child(-1n+3)')
|
289
|
+
assert_tokens([ [:IDENT, 'x'],
|
290
|
+
[':', ':'],
|
291
|
+
[:FUNCTION, 'nth-child('],
|
292
|
+
[:MINUS, '-'],
|
293
|
+
[:NUMBER, '1'],
|
294
|
+
[:IDENT, 'n'],
|
295
|
+
[:PLUS, '+'],
|
296
|
+
[:NUMBER, '3'],
|
297
|
+
[:RPAREN, ')'],
|
298
|
+
], @scanner)
|
299
|
+
|
300
|
+
@scanner.scan('x:nth-child(-n+3)')
|
301
|
+
assert_tokens([ [:IDENT, 'x'],
|
302
|
+
[':', ':'],
|
303
|
+
[:FUNCTION, 'nth-child('],
|
304
|
+
[:IDENT, '-n'],
|
305
|
+
[:PLUS, '+'],
|
306
|
+
[:NUMBER, '3'],
|
307
|
+
[:RPAREN, ')'],
|
308
|
+
], @scanner)
|
309
|
+
end
|
310
|
+
|
311
|
+
def assert_tokens(tokens, scanner)
|
312
|
+
toks = []
|
313
|
+
while tok = @scanner.next_token
|
314
|
+
toks << tok
|
315
|
+
end
|
316
|
+
assert_equal(tokens, toks)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
data/test/helper.rb
CHANGED
@@ -9,7 +9,7 @@ module CSSPool
|
|
9
9
|
|
10
10
|
ASSET_DIR = File.join(File.dirname(__FILE__), 'files')
|
11
11
|
|
12
|
-
class MyDoc < CSSPool::
|
12
|
+
class MyDoc < CSSPool::CSS::DocumentHandler
|
13
13
|
attr_accessor :start_documents, :end_documents
|
14
14
|
attr_accessor :charsets, :import_styles, :comments, :start_selectors
|
15
15
|
attr_accessor :end_selectors, :properties
|
@@ -41,7 +41,7 @@ module CSSPool
|
|
41
41
|
@charsets << [name, location]
|
42
42
|
end
|
43
43
|
|
44
|
-
def import_style media_list, uri, default_ns, location
|
44
|
+
def import_style media_list, uri, default_ns = nil, location = {}
|
45
45
|
@import_styles << [media_list, uri, default_ns, location]
|
46
46
|
end
|
47
47
|
|
data/test/sac/test_parser.rb
CHANGED
@@ -35,15 +35,13 @@ module CSSPool
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_charset
|
38
|
-
assert_equal(
|
39
|
-
[["UTF-8", { :line => 1, :byte_offset => 10, :column => 11}]],
|
40
|
-
@doc.charsets)
|
38
|
+
assert_equal("UTF-8", @doc.charsets.first.first)
|
41
39
|
end
|
42
40
|
|
43
41
|
def test_import_style
|
44
42
|
styles = @doc.import_styles.first
|
45
|
-
assert_equal
|
46
|
-
assert_equal "foo.css", styles[1]
|
43
|
+
assert_equal "screen", styles.first.first.value
|
44
|
+
assert_equal "foo.css", styles[1].value
|
47
45
|
assert_nil styles[2]
|
48
46
|
end
|
49
47
|
|
@@ -57,9 +55,6 @@ module CSSPool
|
|
57
55
|
selectors_for_rule = @doc.start_selectors.first
|
58
56
|
selector = selectors_for_rule.first # => div a.foo
|
59
57
|
assert_equal 2, selector.simple_selectors.length
|
60
|
-
selector.simple_selectors.each do |ss|
|
61
|
-
assert ss.parse_location
|
62
|
-
end
|
63
58
|
end
|
64
59
|
|
65
60
|
def test_additional_selector_list
|
data/test/sac/test_terms.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require 'helper'
|
2
3
|
|
3
4
|
module CSSPool
|
@@ -21,23 +22,21 @@ module CSSPool
|
|
21
22
|
div { border: rgb(1,2,3); }
|
22
23
|
eocss
|
23
24
|
color = @doc.properties.first[1].first
|
24
|
-
assert_equal 1, color.red
|
25
|
-
assert_equal 2, color.green
|
26
|
-
assert_equal 3, color.blue
|
27
|
-
|
28
|
-
assert_match('rgb(1,2,3)', color.to_css)
|
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
29
|
end
|
30
30
|
|
31
31
|
def test_rgb_with_percentage
|
32
32
|
@parser.parse <<-eocss
|
33
|
-
div { border: rgb(100%,2%,3%); }
|
33
|
+
div { border: rgb(100%, 2%, 3%); }
|
34
34
|
eocss
|
35
35
|
color = @doc.properties.first[1].first
|
36
|
-
assert_equal 100, color.red
|
37
|
-
assert_equal 2, color.green
|
38
|
-
assert_equal 3, color.blue
|
39
|
-
|
40
|
-
assert_match('rgb(100%,2%,3%)', color.to_css)
|
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)
|
41
40
|
end
|
42
41
|
|
43
42
|
def test_negative_number
|
@@ -48,8 +47,8 @@ module CSSPool
|
|
48
47
|
size = @doc.properties.first[1].first
|
49
48
|
assert_equal :minus, size.unary_operator
|
50
49
|
assert_equal 1, size.value
|
51
|
-
assert_equal '-
|
52
|
-
assert_equal '-
|
50
|
+
assert_equal '-1px', size.to_s
|
51
|
+
assert_equal '-1px', size.to_css
|
53
52
|
end
|
54
53
|
|
55
54
|
def test_positive_number
|
@@ -59,13 +58,12 @@ module CSSPool
|
|
59
58
|
assert_equal 1, @doc.properties.length
|
60
59
|
size = @doc.properties.first[1].first
|
61
60
|
assert_equal 1, size.value
|
62
|
-
assert_equal '
|
61
|
+
assert_equal '1px', size.to_s
|
63
62
|
end
|
64
63
|
|
65
64
|
%w{
|
66
65
|
1 1em 1ex 1px 1in 1cm 1mm 1pt 1pc 1% 1deg 1rad 1ms 1s 1Hz 1kHz
|
67
66
|
}.each do |num|
|
68
|
-
expected = num.sub(/1/, '1.0')
|
69
67
|
define_method(:"test_num_#{num}") do
|
70
68
|
@parser.parse <<-eocss
|
71
69
|
div { border: #{num}; }
|
@@ -73,19 +71,68 @@ module CSSPool
|
|
73
71
|
assert_equal 1, @doc.properties.length
|
74
72
|
size = @doc.properties.first[1].first
|
75
73
|
assert_equal 1, size.value
|
76
|
-
assert_equal
|
77
|
-
assert_equal
|
74
|
+
assert_equal num, size.to_s
|
75
|
+
assert_equal num, size.to_css
|
78
76
|
end
|
79
77
|
end
|
80
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
|
+
|
81
107
|
def test_string_term
|
82
108
|
@parser.parse <<-eocss
|
83
|
-
div {
|
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 "; }
|
84
115
|
eocss
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
assert_equal '
|
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."
|
89
136
|
end
|
90
137
|
|
91
138
|
def test_inherit
|
@@ -108,26 +155,73 @@ module CSSPool
|
|
108
155
|
assert_equal 'inherit', string.to_css
|
109
156
|
end
|
110
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
|
+
|
111
177
|
def test_function
|
112
178
|
@parser.parse <<-eocss
|
113
|
-
div {
|
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); }
|
114
183
|
eocss
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
assert_equal
|
119
|
-
|
120
|
-
|
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."
|
121
198
|
end
|
122
199
|
|
123
200
|
def test_uri
|
124
201
|
@parser.parse <<-eocss
|
125
|
-
div {
|
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/\\"); }
|
126
207
|
eocss
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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"
|
131
225
|
end
|
132
226
|
end
|
133
227
|
end
|
data/test/test_collection.rb
CHANGED
data/test/test_parser.rb
CHANGED
@@ -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
|
@@ -7,6 +7,21 @@ module CSSPool
|
|
7
7
|
doc1 = CSSPool.CSS css
|
8
8
|
doc2 = CSSPool.CSS css
|
9
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
|
10
25
|
end
|
11
26
|
|
12
27
|
def test_not_equal
|
@@ -18,6 +33,22 @@ module CSSPool
|
|
18
33
|
equalitest 'div { border: #123; }'
|
19
34
|
end
|
20
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
|
+
|
21
52
|
def test_rgb
|
22
53
|
equalitest 'div { border: rgb(1,2,3); }'
|
23
54
|
end
|
@@ -37,7 +68,6 @@ module CSSPool
|
|
37
68
|
%w{
|
38
69
|
1 1em 1ex 1px 1in 1cm 1mm 1pt 1pc 1% 1deg 1rad 1ms 1s 1Hz 1kHz
|
39
70
|
}.each do |num|
|
40
|
-
expected = num.sub(/1/, '1.0')
|
41
71
|
define_method(:"test_num_#{num}") do
|
42
72
|
equalitest "div { border: #{num}; }"
|
43
73
|
end
|