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   20844 use strict;
  2         5  
  2         53  
4 2     2   10 use warnings;
  2         5  
  2         62  
5              
6 2     2   11 use Carp;
  2         6  
  2         173  
7 2     2   1317 use Log::Log4perl qw(:easy);
  2         65091  
  2         20  
8 2     2   3594 use CSS::Selector::Parser qw/parse_selector/;
  2         37055  
  2         18  
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 27 my $class = shift;
23 6         54 return bless ({}, $class);
24             }
25              
26             sub parse_css {
27 13     13 0 18550 my $self = shift;
28 13         23 my $source = shift;
29              
30 13         23 my %classes;
31             my %ids;
32              
33 13         47 $self->_parse_css($source, \%classes, \%ids);
34            
35 13         55 return (\%classes, \%ids);
36             }
37              
38             sub _parse_css {
39 14     14   22 my $self = shift;
40 14         32 my ($source, $classes, $ids) = @_;
41              
42 14         62 $source =~s|/\*.*?\*/||gs; # remove comments
43              
44 14         655 while ($source =~ m/(.*?)($nested)/gs) {
45 25         96 my ($selector, $selector_body) = ($1, $2);
46              
47 25 100       105 if ($selector =~/\s*\@media/s) {
    50          
48 1 50       6 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         38 eval {
57 24         78 foreach (parse_selector($selector)) {
58 28 50       4129 next unless (ref $_ eq 'ARRAY');
59 28         40 foreach my $rule (@{$_}) {
  28         62  
60 28 100       70 if (exists $rule->{class}) {
61             # Bug, selector for .foo.bar return class foo.bar
62             # so split this selector by "."
63 19         57 foreach my $classname (split /\./, $rule->{class}) {
64             $classes->{
65             exists ($rule->{element}) ? $rule->{element} : "global"
66 21 100       104 }{ $classname }++;
67             }
68             }
69 28 100       94 if (exists $rule->{id}) {
70             $ids->{
71             exists ($rule->{element}) ? $rule->{element} : "global"
72 9 100       55 }{ $rule->{id} }++;
73             }
74             }
75             }
76             };
77 24 50       761 if ($@) {
78             # log selector parse failure
79 0           ERROR "Can't parse selector: \"$selector\"";
80             }
81             }
82             }
83              
84              
85             1;
86              
87             __END__