File Coverage

lib/CSS/Watcher/Parser.pm
Criterion Covered Total %
statement 42 44 95.4
branch 14 18 77.7
condition n/a
subroutine 8 8 100.0
pod 0 2 0.0
total 64 72 88.8


line stmt bran cond sub pod time code
1             package CSS::Watcher::Parser;
2              
3 2     2   20665 use strict;
  2         4  
  2         49  
4 2     2   10 use warnings;
  2         4  
  2         53  
5              
6 2     2   9 use Carp;
  2         7  
  2         152  
7 2     2   1283 use Log::Log4perl qw(:easy);
  2         59604  
  2         16  
8 2     2   2962 use CSS::Selector::Parser qw/parse_selector/;
  2         35288  
  2         15  
9              
10             my $nested; # regexp for "{ }"
11             $nested = qr/
12             \{
13             (
14             [^{}]
15             |
16             (??{ $nested })
17             )*
18             \}
19             /x;
20              
21             sub new {
22 6     6 0 19 my $class = shift;
23 6         51 return bless ({}, $class);
24             }
25              
26             sub parse_css {
27 13     13 0 15920 my $self = shift;
28 13         22 my $source = shift;
29              
30 13         19 my %classes;
31             my %ids;
32              
33 13         41 $self->_parse_css($source, \%classes, \%ids);
34            
35 13         55 return (\%classes, \%ids);
36             }
37              
38             sub _parse_css {
39 14     14   20 my $self = shift;
40 14         29 my ($source, $classes, $ids) = @_;
41              
42 14         65 $source =~s|/\*.*?\*/||gs; # remove comments
43              
44 14         736 while ($source =~ m/(.*?)($nested)/gs) {
45 25         106 my ($selector, $selector_body) = ($1, $2);
46              
47 25 100       108 if ($selector =~/\s*\@media/s) {
    50          
48 1 50       8 if ($selector_body =~m /\{(.+)\}/s) {
49 1         7 $self->_parse_css($1, $classes, $ids);
50             }
51 1         25 next;
52             } elsif ($selector =~/\s*\@/s) {
53             # ignore @keyframes, etc @..
54 0         0 next;
55             }
56 24         41 eval {
57 24         78 foreach (parse_selector($selector)) {
58 28 50       4762 next unless (ref $_ eq 'ARRAY');
59 28         39 foreach my $rule (@{$_}) {
  28         60  
60 28 100       69 if (exists $rule->{class}) {
61             # Bug, selector for .foo.bar return class foo.bar
62             # so split this selector by "."
63 19         59 foreach my $classname (split /\./, $rule->{class}) {
64             $classes->{
65             exists ($rule->{element}) ? $rule->{element} : "global"
66 21 100       106 }{ $classname }++;
67             }
68             }
69 28 100       99 if (exists $rule->{id}) {
70             $ids->{
71             exists ($rule->{element}) ? $rule->{element} : "global"
72 9 100       56 }{ $rule->{id} }++;
73             }
74             }
75             }
76             };
77 24 50       793 if ($@) {
78             # log selector parse failure
79 0           ERROR "Can't parse selector: \"$selector\"";
80             }
81             }
82             }
83              
84              
85             1;
86              
87             __END__