crass 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OGNiZTc1MDI4ZWMwYmQxZGI4ODE4Yzc1YzNkNTU2MDJjODc1NTI0Mg==
4
+ MDM3ZDU2Y2U1NDBkNGQxMDQwMzNhNGM1YTRjM2UyM2RjMTA5MGU5MA==
5
5
  data.tar.gz: !binary |-
6
- NTdlYmJkNTZlYjI3ZjE3Njc2ZDRiMzkxYWZjOTQ0OWE3ZTcxYWRiOQ==
6
+ YTMyMDVkZTViMjEyNjVlMGJkNjE2N2M0MWRhYmQ3Mzc3NGU0YzE3Mg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZjA0NTZkOTAwYTYwZmNjMDgyMzE1N2NkZDQ5ZTlkNDg0NzZmYTk4OGNiMjli
10
- MDdlNzQwNTAwZWZmMjkzY2U3N2NkMjEyOWU1ZDMyZWZlYjU1NGRjNzg1Y2Ez
11
- ZWZiYjg5ZTk2YmFhNWQ4NDk1ZDEzNmUwYjg2NDE0NjkyNzFmMjY=
9
+ ZDkwYmUyNGVkZjA5NGMwOWRlNzVlYmIwMmM5NjJlMDYxYWYxMzE0YzE2YWNl
10
+ MTYwZDU4MzZmMTkwZGVmMDk3ODI4MTMwZmE0NWQ3Y2M5ODE1MTllYjhlZWI2
11
+ NmQxMjExYmEzMmI1MTQzOWExOTk1Yjg0NjlkODNiYzM5ZDIwZjk=
12
12
  data.tar.gz: !binary |-
13
- NTE5NzI2MDViOWU5YzE4NzFmOWNlZmU0MWM5NTJhNGIyZTMyMTBkOGVjNWQ5
14
- MmQ5NDZhYWY5YjIzMTgyNzNjNzZmY2I1NDE3YzFmMzM2Njk1NGQzMzQ3OTkw
15
- MjFmODllYmM5NDQ5MTk3YjAwN2I3M2NmNzU4NDZkYzQwYzE1NWE=
13
+ OTQ4N2Y4MWNiYjQzNTdlN2MzMDVjMTRhY2U2NjE4YzczNDgwMzVhYzQ5ODcy
14
+ NjMwYTRhZmNiOTc5ZjViMjgyYzlhZThkOWU2Yjc5ODI4YTJlNDUzNmQ1ODAy
15
+ MTQ2YTA2ZDhmZWUzNDMwNDk2NjQ2MDk4OTBmNmI5NDdmOTNlNzE=
data/HISTORY.md CHANGED
@@ -1,6 +1,20 @@
1
1
  Crass Change History
2
2
  ====================
3
3
 
4
+ 0.2.0 (2013-10-10)
5
+ ------------------
6
+
7
+ * Added a `:children` field to `:property` nodes. It's an array containing all
8
+ the nodes that make up the property's value.
9
+
10
+ * Fixed: Incorrect value was given for `:property` nodes whose values contained
11
+ functions.
12
+
13
+ * Fixed: When parsing the value of an at-rule's block as a list of rules, a
14
+ selector containing a function (such as "#foo:not(.bar)") would cause that
15
+ property and the rest of the token stream to be discarded.
16
+
17
+
4
18
  0.1.0 (2013-10-04)
5
19
  ------------------
6
20
 
data/README.md CHANGED
@@ -83,47 +83,57 @@ This returns a big fat ugly parse tree, which looks like this:
83
83
  ```ruby
84
84
  [{:node=>:comment, :pos=>0, :raw=>"/* Comment! */", :value=>" Comment! "},
85
85
  {:node=>:whitespace, :pos=>14, :raw=>"\n"},
86
- {:node=>:style_rule,
87
- :selector=>
88
- {:node=>:selector,
89
- :value=>"a:hover",
90
- :tokens=>
91
- [{:node=>:ident, :pos=>15, :raw=>"a", :value=>"a"},
92
- {:node=>:colon, :pos=>16, :raw=>":"},
93
- {:node=>:ident, :pos=>17, :raw=>"hover", :value=>"hover"},
94
- {:node=>:whitespace, :pos=>22, :raw=>" "}]},
86
+ {:node=>:property,
87
+ :name=>"a",
88
+ :value=>"hover {\n color: #0d8bfa",
95
89
  :children=>
96
- [{:node=>:whitespace, :pos=>24, :raw=>"\n "},
97
- {:node=>:property,
98
- :name=>"color",
99
- :value=>"#0d8bfa",
100
- :important=>false,
101
- :tokens=>
102
- [{:node=>:ident, :pos=>27, :raw=>"color", :value=>"color"},
103
- {:node=>:colon, :pos=>32, :raw=>":"},
104
- {:node=>:whitespace, :pos=>33, :raw=>" "},
105
- {:node=>:hash,
106
- :pos=>34,
107
- :raw=>"#0d8bfa",
108
- :type=>:unrestricted,
109
- :value=>"0d8bfa"},
110
- {:node=>:semicolon, :pos=>41, :raw=>";"}]},
111
- {:node=>:whitespace, :pos=>42, :raw=>"\n "},
112
- {:node=>:property,
113
- :name=>"text-decoration",
114
- :value=>"underline",
115
- :important=>false,
116
- :tokens=>
117
- [{:node=>:ident,
118
- :pos=>45,
119
- :raw=>"text-decoration",
120
- :value=>"text-decoration"},
121
- {:node=>:colon, :pos=>60, :raw=>":"},
122
- {:node=>:whitespace, :pos=>61, :raw=>" "},
123
- {:node=>:ident, :pos=>62, :raw=>"underline", :value=>"underline"},
124
- {:node=>:semicolon, :pos=>71, :raw=>";"}]},
125
- {:node=>:whitespace, :pos=>72, :raw=>"\n"}]},
126
- {:node=>:whitespace, :pos=>74, :raw=>"\n"}]
90
+ [{:node=>:ident, :pos=>17, :raw=>"hover", :value=>"hover"},
91
+ {:node=>:whitespace, :pos=>22, :raw=>" "},
92
+ {:node=>:"{", :pos=>23, :raw=>"{"},
93
+ {:node=>:whitespace, :pos=>24, :raw=>"\n "},
94
+ {:node=>:ident, :pos=>27, :raw=>"color", :value=>"color"},
95
+ {:node=>:colon, :pos=>32, :raw=>":"},
96
+ {:node=>:whitespace, :pos=>33, :raw=>" "},
97
+ {:node=>:hash,
98
+ :pos=>34,
99
+ :raw=>"#0d8bfa",
100
+ :type=>:unrestricted,
101
+ :value=>"0d8bfa"}],
102
+ :important=>false,
103
+ :tokens=>
104
+ [{:node=>:ident, :pos=>15, :raw=>"a", :value=>"a"},
105
+ {:node=>:colon, :pos=>16, :raw=>":"},
106
+ {:node=>:ident, :pos=>17, :raw=>"hover", :value=>"hover"},
107
+ {:node=>:whitespace, :pos=>22, :raw=>" "},
108
+ {:node=>:"{", :pos=>23, :raw=>"{"},
109
+ {:node=>:whitespace, :pos=>24, :raw=>"\n "},
110
+ {:node=>:ident, :pos=>27, :raw=>"color", :value=>"color"},
111
+ {:node=>:colon, :pos=>32, :raw=>":"},
112
+ {:node=>:whitespace, :pos=>33, :raw=>" "},
113
+ {:node=>:hash,
114
+ :pos=>34,
115
+ :raw=>"#0d8bfa",
116
+ :type=>:unrestricted,
117
+ :value=>"0d8bfa"},
118
+ {:node=>:semicolon, :pos=>41, :raw=>";"}]},
119
+ {:node=>:whitespace, :pos=>42, :raw=>"\n "},
120
+ {:node=>:property,
121
+ :name=>"text-decoration",
122
+ :value=>"underline",
123
+ :children=>
124
+ [{:node=>:whitespace, :pos=>61, :raw=>" "},
125
+ {:node=>:ident, :pos=>62, :raw=>"underline", :value=>"underline"}],
126
+ :important=>false,
127
+ :tokens=>
128
+ [{:node=>:ident,
129
+ :pos=>45,
130
+ :raw=>"text-decoration",
131
+ :value=>"text-decoration"},
132
+ {:node=>:colon, :pos=>60, :raw=>":"},
133
+ {:node=>:whitespace, :pos=>61, :raw=>" "},
134
+ {:node=>:ident, :pos=>62, :raw=>"underline", :value=>"underline"},
135
+ {:node=>:semicolon, :pos=>71, :raw=>";"}]},
136
+ {:node=>:whitespace, :pos=>72, :raw=>"\n"}]
127
137
  ```
128
138
 
129
139
  If you want, you can stringify the parse tree:
@@ -26,7 +26,7 @@ module Crass
26
26
  Parser.new(input, options).parse_properties
27
27
  end
28
28
 
29
- # Parses a CSS rules (such as the content of a `@media` block) and returns a
29
+ # Parses CSS rules (such as the content of a `@media` block) and returns a
30
30
  # parse tree. The only difference from {#parse_stylesheet} is that CDO/CDC
31
31
  # nodes (`<!--` and `-->`) aren't ignored.
32
32
  #
@@ -143,10 +143,13 @@ module Crass
143
143
 
144
144
  while token = input.consume
145
145
  case token[:node]
146
- when :comment then next
147
- when :semicolon, :eof then break
146
+ when :comment
147
+ next
148
148
 
149
- when :'{' then
149
+ when :semicolon
150
+ break
151
+
152
+ when :'{'
150
153
  rule[:block] = consume_simple_block(input)
151
154
  break
152
155
 
@@ -171,14 +174,24 @@ module Crass
171
174
 
172
175
  # Consumes a component value and returns it.
173
176
  #
174
- # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-component-value0
177
+ # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-component-value
175
178
  def consume_component_value(input = @tokens)
176
179
  return nil unless token = input.consume
177
180
 
178
181
  case token[:node]
179
- when :'{', :'[', :'(' then consume_simple_block(input)
180
- when :function then consume_function(input)
181
- else token
182
+ when :'{', :'[', :'('
183
+ consume_simple_block(input)
184
+
185
+ when :function
186
+ if token.key?(:name)
187
+ # This is a parsed function, not a function token.
188
+ token
189
+ else
190
+ consume_function(input)
191
+ end
192
+
193
+ else
194
+ token
182
195
  end
183
196
  end
184
197
 
@@ -291,18 +304,21 @@ module Crass
291
304
  :tokens => [input.current]
292
305
  }
293
306
 
294
- function[:tokens].concat(input.collect do
307
+ function[:tokens].concat(input.collect {
295
308
  while token = input.consume
296
309
  case token[:node]
297
- when :')', :eof then break
298
- when :comment then next
310
+ when :')'
311
+ break
312
+
313
+ when :comment
314
+ next
299
315
 
300
316
  else
301
317
  input.reconsume
302
318
  function[:value] << consume_component_value(input)
303
319
  end
304
320
  end
305
- end)
321
+ })
306
322
 
307
323
  create_node(:function, function)
308
324
  end
@@ -340,12 +356,10 @@ module Crass
340
356
  def consume_rules(flags = {})
341
357
  rules = []
342
358
 
343
- while true
344
- return rules unless token = @tokens.consume
345
-
359
+ while token = @tokens.consume
346
360
  case token[:node]
347
- when :comment, :whitespace then rules << token
348
- when :eof then return rules
361
+ when :comment, :whitespace
362
+ rules << token
349
363
 
350
364
  when :cdc, :cdo
351
365
  unless flags[:top_level]
@@ -365,6 +379,8 @@ module Crass
365
379
  rules << rule if rule
366
380
  end
367
381
  end
382
+
383
+ rules
368
384
  end
369
385
 
370
386
  # Consumes and returns a simple block associated with the current input
@@ -384,7 +400,7 @@ module Crass
384
400
 
385
401
  block[:tokens].concat(input.collect do
386
402
  while token = input.consume
387
- break if token[:node] == end_token || token[:node] == :eof
403
+ break if token[:node] == end_token
388
404
 
389
405
  input.reconsume
390
406
  block[:value] << consume_component_value(input)
@@ -435,9 +451,13 @@ module Crass
435
451
  next
436
452
  end
437
453
 
454
+ children = decl[:value].dup
455
+ children.pop if children.last[:node] == :semicolon
456
+
438
457
  properties << create_node(:property,
439
458
  :name => decl[:name],
440
459
  :value => parse_value(decl[:value]),
460
+ :children => children,
441
461
  :important => decl[:important] == true,
442
462
  :tokens => decl[:tokens])
443
463
  end
@@ -452,7 +472,8 @@ module Crass
452
472
 
453
473
  nodes.each do |node|
454
474
  case node[:node]
455
- when :comment, :semicolon then next
475
+ when :comment, :semicolon
476
+ next
456
477
 
457
478
  when :at_keyword, :ident
458
479
  string << node[:value]
@@ -460,8 +481,9 @@ module Crass
460
481
  when :function
461
482
  if node[:value].is_a?(String)
462
483
  string << node[:value]
484
+ string << '('
463
485
  else
464
- string << parse_value(node[:value])
486
+ string << parse_value(node[:tokens])
465
487
  end
466
488
 
467
489
  else
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Crass
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -188,6 +188,11 @@ shared_tests_for 'parsing a list of rules' do
188
188
  assert_equal("#aaa", property[:value])
189
189
  assert_equal(false, property[:important])
190
190
  assert_tokens("color: #aaa;", property[:tokens], 16)
191
+
192
+ assert_equal([
193
+ {:node=>:whitespace, :pos=>22, :raw=>" "},
194
+ {:node=>:hash, :pos=>23, :raw=>"#aaa", :type=>:id, :value=>"aaa"},
195
+ ], property[:children])
191
196
  end
192
197
 
193
198
  it 'with preceding comment, selector, block, comment, when :preserve_comments == true' do
@@ -217,6 +222,11 @@ shared_tests_for 'parsing a list of rules' do
217
222
  assert_equal("#aaa", property[:value])
218
223
  assert_equal(false, property[:important])
219
224
  assert_tokens("color: #aaa;", property[:tokens], 16, options)
225
+
226
+ assert_equal([
227
+ {:node=>:whitespace, :pos=>22, :raw=>" "},
228
+ {:node=>:hash, :pos=>23, :raw=>"#aaa", :type=>:id, :value=>"aaa"}
229
+ ], property[:children])
220
230
  end
221
231
 
222
232
  it 'unclosed, with preceding comment, no selector' do
@@ -243,6 +253,12 @@ shared_tests_for 'parsing a list of rules' do
243
253
  assert_equal("#aaa", property[:value])
244
254
  assert_equal(false, property[:important])
245
255
  assert_tokens("color: #aaa ", property[:tokens], 8)
256
+
257
+ assert_equal([
258
+ {:node=>:whitespace, :pos=>14, :raw=>" "},
259
+ {:node=>:hash, :pos=>15, :raw=>"#aaa", :type=>:id, :value=>"aaa"},
260
+ {:node=>:whitespace, :pos=>19, :raw=>" "}
261
+ ], property[:children])
246
262
  end
247
263
 
248
264
  it 'unclosed, with preceding comment, no selector, when :preserve_comments == true' do
@@ -270,6 +286,12 @@ shared_tests_for 'parsing a list of rules' do
270
286
  assert_equal("#aaa", property[:value])
271
287
  assert_equal(false, property[:important])
272
288
  assert_tokens("color: #aaa ", property[:tokens], 8, options)
289
+
290
+ assert_equal([
291
+ {:node=>:whitespace, :pos=>14, :raw=>" "},
292
+ {:node=>:hash, :pos=>15, :raw=>"#aaa", :type=>:id, :value=>"aaa"},
293
+ {:node=>:whitespace, :pos=>19, :raw=>" "}
294
+ ], property[:children])
273
295
  end
274
296
  end
275
297
 
@@ -298,6 +320,11 @@ shared_tests_for 'parsing a list of rules' do
298
320
  assert_equal(false, prop[:important])
299
321
  assert_tokens("color: #aaa;", prop[:tokens], 6)
300
322
 
323
+ assert_equal([
324
+ {:node=>:whitespace, :pos=>12, :raw=>" "},
325
+ {:node=>:hash, :pos=>13, :raw=>"#aaa", :type=>:id, :value=>"aaa"}
326
+ ], prop[:children])
327
+
301
328
  assert_tokens(" ", tree[1], 20)
302
329
 
303
330
  rule = tree[2]
@@ -342,4 +369,152 @@ shared_tests_for 'parsing a list of rules' do
342
369
  assert_equal([], rule[:prelude])
343
370
  assert_tokens("@a", rule[:tokens], 2)
344
371
  end
372
+
373
+ it 'should parse property values containing functions' do
374
+ tree = parse("p:before { content: a\\ttr(data-foo) \" \"; }")
375
+
376
+ assert_equal([
377
+ {:node=>:style_rule,
378
+ :selector=>
379
+ {:node=>:selector,
380
+ :value=>"p:before",
381
+ :tokens=>
382
+ [{:node=>:ident, :pos=>0, :raw=>"p", :value=>"p"},
383
+ {:node=>:colon, :pos=>1, :raw=>":"},
384
+ {:node=>:ident, :pos=>2, :raw=>"before", :value=>"before"},
385
+ {:node=>:whitespace, :pos=>8, :raw=>" "}]},
386
+ :children=>
387
+ [{:node=>:whitespace, :pos=>10, :raw=>" "},
388
+ {:node=>:property,
389
+ :name=>"content",
390
+ :value=>"attr(data-foo) \" \"",
391
+ :important=>false,
392
+ :children=>
393
+ [{:node=>:whitespace, :pos=>19, :raw=>" "},
394
+ {:node=>:function,
395
+ :name=>"attr",
396
+ :value=>
397
+ [{:node=>:ident, :pos=>26, :raw=>"data-foo", :value=>"data-foo"}],
398
+ :tokens=>
399
+ [{:node=>:function, :pos=>20, :raw=>"a\\ttr(", :value=>"attr"},
400
+ {:node=>:ident, :pos=>26, :raw=>"data-foo", :value=>"data-foo"},
401
+ {:node=>:")", :pos=>34, :raw=>")"}]},
402
+ {:node=>:whitespace, :pos=>35, :raw=>" "},
403
+ {:node=>:string, :pos=>36, :raw=>"\" \"", :value=>" "}],
404
+ :tokens=>
405
+ [{:node=>:ident, :pos=>11, :raw=>"content", :value=>"content"},
406
+ {:node=>:colon, :pos=>18, :raw=>":"},
407
+ {:node=>:whitespace, :pos=>19, :raw=>" "},
408
+ {:node=>:function,
409
+ :name=>"attr",
410
+ :value=>
411
+ [{:node=>:ident, :pos=>26, :raw=>"data-foo", :value=>"data-foo"}],
412
+ :tokens=>
413
+ [{:node=>:function, :pos=>20, :raw=>"a\\ttr(", :value=>"attr"},
414
+ {:node=>:ident, :pos=>26, :raw=>"data-foo", :value=>"data-foo"},
415
+ {:node=>:")", :pos=>34, :raw=>")"}]},
416
+ {:node=>:whitespace, :pos=>35, :raw=>" "},
417
+ {:node=>:string, :pos=>36, :raw=>"\" \"", :value=>" "},
418
+ {:node=>:semicolon, :pos=>39, :raw=>";"}]},
419
+ {:node=>:whitespace, :pos=>40, :raw=>" "}]}
420
+ ], tree)
421
+ end
422
+
423
+ it 'should parse property values containing nested functions' do
424
+ tree = parse("div { width: e\\78 pression(alert(1)); }")
425
+
426
+ assert_equal([
427
+ {:node=>:style_rule,
428
+ :selector=>
429
+ {:node=>:selector,
430
+ :value=>"div",
431
+ :tokens=>
432
+ [{:node=>:ident, :pos=>0, :raw=>"div", :value=>"div"},
433
+ {:node=>:whitespace, :pos=>3, :raw=>" "}]},
434
+ :children=>
435
+ [{:node=>:whitespace, :pos=>5, :raw=>" "},
436
+ {:node=>:property,
437
+ :name=>"width",
438
+ :value=>"expression(alert(1))",
439
+ :important=>false,
440
+ :children=>
441
+ [{:node=>:whitespace, :pos=>12, :raw=>" "},
442
+ {:node=>:function,
443
+ :name=>"expression",
444
+ :value=>
445
+ [{:node=>:function,
446
+ :name=>"alert",
447
+ :value=>
448
+ [{:node=>:number,
449
+ :pos=>33,
450
+ :raw=>"1",
451
+ :repr=>"1",
452
+ :type=>:integer,
453
+ :value=>1}],
454
+ :tokens=>
455
+ [{:node=>:function, :pos=>27, :raw=>"alert(", :value=>"alert"},
456
+ {:node=>:number,
457
+ :pos=>33,
458
+ :raw=>"1",
459
+ :repr=>"1",
460
+ :type=>:integer,
461
+ :value=>1},
462
+ {:node=>:")", :pos=>34, :raw=>")"}]}],
463
+ :tokens=>
464
+ [{:node=>:function,
465
+ :pos=>13,
466
+ :raw=>"e\\78 pression(",
467
+ :value=>"expression"},
468
+ {:node=>:function, :pos=>27, :raw=>"alert(", :value=>"alert"},
469
+ {:node=>:number,
470
+ :pos=>33,
471
+ :raw=>"1",
472
+ :repr=>"1",
473
+ :type=>:integer,
474
+ :value=>1},
475
+ {:node=>:")", :pos=>34, :raw=>")"},
476
+ {:node=>:")", :pos=>35, :raw=>")"}]}],
477
+ :tokens=>
478
+ [{:node=>:ident, :pos=>6, :raw=>"width", :value=>"width"},
479
+ {:node=>:colon, :pos=>11, :raw=>":"},
480
+ {:node=>:whitespace, :pos=>12, :raw=>" "},
481
+ {:node=>:function,
482
+ :name=>"expression",
483
+ :value=>
484
+ [{:node=>:function,
485
+ :name=>"alert",
486
+ :value=>
487
+ [{:node=>:number,
488
+ :pos=>33,
489
+ :raw=>"1",
490
+ :repr=>"1",
491
+ :type=>:integer,
492
+ :value=>1}],
493
+ :tokens=>
494
+ [{:node=>:function, :pos=>27, :raw=>"alert(", :value=>"alert"},
495
+ {:node=>:number,
496
+ :pos=>33,
497
+ :raw=>"1",
498
+ :repr=>"1",
499
+ :type=>:integer,
500
+ :value=>1},
501
+ {:node=>:")", :pos=>34, :raw=>")"}]}],
502
+ :tokens=>
503
+ [{:node=>:function,
504
+ :pos=>13,
505
+ :raw=>"e\\78 pression(",
506
+ :value=>"expression"},
507
+ {:node=>:function, :pos=>27, :raw=>"alert(", :value=>"alert"},
508
+ {:node=>:number,
509
+ :pos=>33,
510
+ :raw=>"1",
511
+ :repr=>"1",
512
+ :type=>:integer,
513
+ :value=>1},
514
+ {:node=>:")", :pos=>34, :raw=>")"},
515
+ {:node=>:")", :pos=>35, :raw=>")"}]},
516
+ {:node=>:semicolon, :pos=>36, :raw=>";"}]},
517
+ {:node=>:whitespace, :pos=>37, :raw=>" "}]}
518
+ ], tree)
519
+ end
345
520
  end
@@ -40,6 +40,10 @@ describe 'Crass::Parser' do
40
40
  assert_equal(false, prop[:important])
41
41
  assert_tokens("a:b;", prop[:tokens])
42
42
 
43
+ assert_equal([
44
+ {:node=>:ident, :pos=>2, :raw=>"b", :value=>"b"}
45
+ ], prop[:children])
46
+
43
47
  assert_tokens(" ", tree[1], 4)
44
48
 
45
49
  prop = tree[2]
@@ -49,6 +53,17 @@ describe 'Crass::Parser' do
49
53
  assert_equal(true, prop[:important])
50
54
  assert_tokens("c:d 42!important;", prop[:tokens], 5)
51
55
 
56
+ assert_equal([
57
+ {:node=>:ident, :pos=>7, :raw=>"d", :value=>"d"},
58
+ {:node=>:whitespace, :pos=>8, :raw=>" "},
59
+ {:node=>:number,
60
+ :pos=>9,
61
+ :raw=>"42",
62
+ :repr=>"42",
63
+ :type=>:integer,
64
+ :value=>42}
65
+ ], prop[:children])
66
+
52
67
  assert_tokens("\n", tree[3], 22)
53
68
  end
54
69
 
@@ -71,6 +86,10 @@ describe 'Crass::Parser' do
71
86
  assert_equal(false, prop[:important])
72
87
  assert_tokens("a:b;", prop[:tokens], 19)
73
88
 
89
+ assert_equal([
90
+ {:node=>:ident, :pos=>21, :raw=>"b", :value=>"b"}
91
+ ], prop[:children])
92
+
74
93
  assert_tokens(" ", tree[3], 23)
75
94
 
76
95
  rule = tree[4]
@@ -115,6 +134,9 @@ describe 'Crass::Parser' do
115
134
  assert_equal("b", prop[:value])
116
135
  assert_equal(false, prop[:important])
117
136
  assert_tokens("a:b;", prop[:tokens], 24)
137
+ assert_equal([
138
+ {:node=>:ident, :pos=>26, :raw=>"b", :value=>"b"}
139
+ ], prop[:children])
118
140
 
119
141
  assert_tokens("; ", tree[3..4], 28)
120
142
 
@@ -171,5 +193,71 @@ describe 'Crass::Parser' do
171
193
  assert_equal([], block[:value])
172
194
  assert_tokens("{", block[:tokens], 47)
173
195
  end
196
+
197
+ it 'should parse values containing functions' do
198
+ tree = parse("content: attr(data-foo) \" \";")
199
+
200
+ assert_equal([
201
+ {:node=>:property,
202
+ :name=>"content",
203
+ :value=>"attr(data-foo) \" \"",
204
+ :important=>false,
205
+ :children=>
206
+ [{:node=>:whitespace, :pos=>8, :raw=>" "},
207
+ {:node=>:function, :pos=>9, :raw=>"attr(", :value=>"attr"},
208
+ {:node=>:ident, :pos=>14, :raw=>"data-foo", :value=>"data-foo"},
209
+ {:node=>:")", :pos=>22, :raw=>")"},
210
+ {:node=>:whitespace, :pos=>23, :raw=>" "},
211
+ {:node=>:string, :pos=>24, :raw=>"\" \"", :value=>" "}],
212
+ :tokens=>
213
+ [{:node=>:ident, :pos=>0, :raw=>"content", :value=>"content"},
214
+ {:node=>:colon, :pos=>7, :raw=>":"},
215
+ {:node=>:whitespace, :pos=>8, :raw=>" "},
216
+ {:node=>:function, :pos=>9, :raw=>"attr(", :value=>"attr"},
217
+ {:node=>:ident, :pos=>14, :raw=>"data-foo", :value=>"data-foo"},
218
+ {:node=>:")", :pos=>22, :raw=>")"},
219
+ {:node=>:whitespace, :pos=>23, :raw=>" "},
220
+ {:node=>:string, :pos=>24, :raw=>"\" \"", :value=>" "},
221
+ {:node=>:semicolon, :pos=>27, :raw=>";"}]}
222
+ ], tree)
223
+ end
224
+
225
+ it 'should parse values containing nested functions' do
226
+ tree = parse("width: expression(alert(1));")
227
+
228
+ assert_equal([
229
+ {:node=>:property,
230
+ :name=>"width",
231
+ :value=>"expression(alert(1))",
232
+ :important=>false,
233
+ :children=>
234
+ [{:node=>:whitespace, :pos=>6, :raw=>" "},
235
+ {:node=>:function, :pos=>7, :raw=>"expression(", :value=>"expression"},
236
+ {:node=>:function, :pos=>18, :raw=>"alert(", :value=>"alert"},
237
+ {:node=>:number,
238
+ :pos=>24,
239
+ :raw=>"1",
240
+ :repr=>"1",
241
+ :type=>:integer,
242
+ :value=>1},
243
+ {:node=>:")", :pos=>25, :raw=>")"},
244
+ {:node=>:")", :pos=>26, :raw=>")"}],
245
+ :tokens=>
246
+ [{:node=>:ident, :pos=>0, :raw=>"width", :value=>"width"},
247
+ {:node=>:colon, :pos=>5, :raw=>":"},
248
+ {:node=>:whitespace, :pos=>6, :raw=>" "},
249
+ {:node=>:function, :pos=>7, :raw=>"expression(", :value=>"expression"},
250
+ {:node=>:function, :pos=>18, :raw=>"alert(", :value=>"alert"},
251
+ {:node=>:number,
252
+ :pos=>24,
253
+ :raw=>"1",
254
+ :repr=>"1",
255
+ :type=>:integer,
256
+ :value=>1},
257
+ {:node=>:")", :pos=>25, :raw=>")"},
258
+ {:node=>:")", :pos=>26, :raw=>")"},
259
+ {:node=>:semicolon, :pos=>27, :raw=>";"}]}
260
+ ], tree)
261
+ end
174
262
  end
175
263
  end
@@ -52,12 +52,12 @@ describe 'Crass::Parser' do
52
52
  end
53
53
 
54
54
  it 'should parse the block of an at-rule' do
55
- rule = CP.parse_stylesheet("@media (max-width: 400px) {.foo{color:#fff;}}")[0]
55
+ rule = CP.parse_stylesheet("@media (max-width: 400px) {#foo:not(.bar){color:#fff;}}")[0]
56
56
  assert_equal(:at_rule, rule[:node])
57
57
 
58
58
  style_rule = parse(rule[:block][:value])[0]
59
59
  assert_equal(:style_rule, style_rule[:node])
60
- assert_equal(".foo", style_rule[:selector][:value])
60
+ assert_equal("#foo:not(.bar)", style_rule[:selector][:value])
61
61
  assert_equal(1, style_rule[:children].size)
62
62
 
63
63
  prop = style_rule[:children][0]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Grove
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-04 00:00:00.000000000 Z
11
+ date: 2013-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest