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