File Coverage

blib/lib/OCBNET/CSS3.pm
Criterion Covered Total %
statement 117 145 80.6
branch 31 42 73.8
condition 3 3 100.0
subroutine 31 36 86.1
pod 0 20 0.0
total 182 246 73.9


line stmt bran cond sub pod time code
1             ###################################################################################################
2             # Copyright 2013/2014 by Marcel Greter
3             # This file is part of OCBNET-CSS3 (GPL3)
4             ####################################################################################################
5             package OCBNET::CSS3;
6             ####################################################################################################
7             our $VERSION = '0.2.7';
8             ####################################################################################################
9            
10 11     11   303190 use strict;
  11         138  
  11         474  
11 11     11   57 use warnings;
  11         17  
  11         455  
12            
13             ####################################################################################################
14            
15             our @types;
16            
17             ####################################################################################################
18            
19             # load other base classes
20 11     11   5805 use OCBNET::CSS3::Stylesheet;
  11         24  
  11         338  
21 11     11   70 use OCBNET::CSS3::DOM::Block;
  11         17  
  11         278  
22             # load different types
23 11     11   6893 use OCBNET::CSS3::DOM::Comment;
  11         32  
  11         318  
24 11     11   12680 use OCBNET::CSS3::DOM::Extended;
  11         36  
  11         477  
25 11     11   6081 use OCBNET::CSS3::DOM::Selector;
  11         40  
  11         672  
26 11     11   7899 use OCBNET::CSS3::DOM::Property;
  11         32  
  11         431  
27 11     11   6276 use OCBNET::CSS3::DOM::Whitespace;
  11         32  
  11         444  
28             # text is the last order
29 11     11   6191 use OCBNET::CSS3::DOM::Text;
  11         28  
  11         424  
30            
31             ####################################################################################################
32            
33             # load regular expressions
34 11     11   59 use OCBNET::CSS3::Regex::Base;
  11         21  
  11         1276  
35 11     11   6959 use OCBNET::CSS3::Regex::Colors;
  11         41  
  11         2623  
36 11     11   116 use OCBNET::CSS3::Regex::Numbers;
  11         21  
  11         2011  
37 11     11   62 use OCBNET::CSS3::Regex::Comments;
  11         20  
  11         1443  
38 11     11   59 use OCBNET::CSS3::Regex::Selectors;
  11         20  
  11         950  
39 11     11   8593 use OCBNET::CSS3::Regex::Stylesheet;
  11         26  
  11         19434  
40            
41             ####################################################################################################
42             # is common base for all classes
43             ####################################################################################################
44            
45             # create a new object
46             # ***************************************************************************************
47             sub new
48             {
49            
50             # package name
51 329     329 0 542 my ($pckg) = shift;
52            
53             # create a new instance
54 329         1540 my $self = {
55            
56             'ids' => {},
57             'text' => undef,
58             'footer' => '',
59             'suffix' => undef,
60             'bracket' => undef,
61             'children' => [],
62            
63             };
64            
65             # bless instance into package
66 329         1136 return bless $self, $pckg;
67            
68             }
69             # EO constructor
70            
71             ####################################################################################################
72            
73             # get statistics object
74             # ***************************************************************************************
75             sub stats
76             {
77            
78 0     0 0 0 my ($node) = @_;
79            
80             # add first object
81 0         0 my @objects = ($node);
82            
83             # array to count items
84 0         0 my (@imports, @selectors);
85            
86             # process as long as we have objects
87 0         0 while (my $object = shift @objects)
88             {
89             # process children array
90 0 0       0 if ($object->{'children'})
91             {
92             # add object to counter arrays
93 0         0 push @objects, @{$object->{'children'}};
  0         0  
94 0 0       0 push @imports, $object if $object->type eq 'import';
95 0 0       0 push @selectors, $object if $object->type eq 'selector';
96             }
97             }
98            
99             # split imports and selectors by commas
100 0         0 @imports = map { split /,/, $_->text } @imports;
  0         0  
101 0         0 @selectors = map { split /,/, $_->text } @selectors;
  0         0  
102            
103             # KB 262161 outlines the maximum number of stylesheets
104             # and rules supported by Internet Explorer 6 to 9.
105             # - A sheet may contain up to 4095 rules
106             # - A sheet may @import up to 31 sheets
107             # - @import nesting supports up to 4 levels deep
108            
109 0         0 return { 'imports' => \@imports, 'selectors' => \@selectors }
110            
111             }
112             # EO stats
113            
114             ####################################################################################################
115            
116             # create a cloned object
117             # ***************************************************************************************
118             sub clone
119             {
120            
121             # get passed arguments
122 54     54 0 104 my ($self, $deep) = @_;
123            
124             # create an empty cloned object
125 54         209 my $clone = ref($self)->new;
126            
127             # clone all basic values
128 54         131 $clone->set($self->text);
129 54         124 $clone->suffix = $self->suffix;
130 54         105 $clone->bracket = $self->bracket;
131            
132             # return now if deep no set
133 54 100       131 return $clone unless $deep;
134            
135             # add a clone of each child to clone
136 53         58 foreach my $child (@{$self->children})
  53         100  
137 35         180 { $clone->add($child->clone($deep)) }
138            
139             # new instance
140 53         173 return $clone;
141            
142             }
143             # EO sub clone
144            
145             ####################################################################################################
146            
147             # static getter (overwrite)
148             # ***************************************************************************************
149 1     1 0 6 sub type { return 'base' }
150            
151             # main setter method
152             # overwrite to parse object
153             # ***************************************************************************************
154 312     312 0 907 sub set { $_[0]->text = $_[1] }
155            
156             # setter and getter
157             # ***************************************************************************************
158 541     541 0 1637 sub text : lvalue { $_[0]->{'text'} }
159 541     541 0 1248 sub suffix : lvalue { $_[0]->{'suffix'} }
160 880     880 0 2190 sub bracket : lvalue { $_[0]->{'bracket'} }
161            
162             # getter (set via reference)
163             # ***************************************************************************************
164 681     681 0 2646 sub parent { $_[0]->{'parent'} }
165 190     190 0 21900 sub children { $_[0]->{'children'} }
166            
167             # get only css block scopes
168             # ***************************************************************************************
169 0     0 0 0 sub blocks { grep { UNIVERSAL::isa($_, 'OCBNET::CSS3::DOM::Block') } @{$_[0]->children} }
  0         0  
  0         0  
170            
171             # get typed blocks in list context
172             # ***************************************************************************************
173 0     0 0 0 sub imports { grep { $_->type eq 'import' } $_[0]->blocks }
  0         0  
174 0     0 0 0 sub selectors { grep { $_->type eq 'selector' } $_[0]->blocks }
  0         0  
175            
176             # get child by index
177             # ***************************************************************************************
178 206     206 0 1248 sub child { $_[0]->{'children'}->[ $_[1] ] }
179            
180             # get the root node (the one without parent)
181             # ***************************************************************************************
182 202 100   202 0 467 sub root { $_[0]->parent ? $_[0]->parent->root : $_[0] }
183            
184             ####################################################################################################
185            
186             # parse given text
187             # attachs new objects
188             sub parse
189             {
190            
191             # get input arguments
192 86     86 0 252 my ($self, $text) = @_;
193            
194             # maybe we should error out here
195 86 50       223 return $self unless defined $text;
196            
197             # parse as much as possible
198             # a stricter version would replace the parsed
199             # code and check the final string to be empty
200 86         7368 while ($text =~ s/\A$re_statement//s)
201             # while ($text =~ m/$re_statement/g)
202             {
203             # declare object
204 256         584 my $object;
205            
206             # store the different parts from the match
207 256 100       833 my $match = defined $1 ? $1 : $2;
208 256         548 my ($scope, $suffix) = ($3, $4);
209            
210             # copy uncommented text
211 256         663 my $code = uncomment $match;
212            
213             # dynamically find type
214 256         490 foreach my $type (@types)
215             {
216             # get options from type array
217 1592         1621 my ($regex, $pckg, $tst) = @{$type};
  1592         2499  
218             # skip if type does not match
219 1592 100       6571 next unless $code =~ m/$regex/s;
220             # call optional test if one is defined
221 476 100 100     1895 next if $tst && ! $tst->($match, $scope);
222             # create new dynamic object
223 256         1160 $object = $pckg->new; last;
  256         419  
224             }
225             # EO each type
226            
227             # create object if no other type found
228 256 50       717 $object = new OCBNET::CSS3 unless $object;
229            
230             # add object to scope
231 256         888 $self->add($object);
232            
233             # set the main text
234 256         801 $object->set($match);
235            
236             # set to the parsed suffix
237 256         735 $object->suffix = $suffix;
238            
239             # set scope status if we have parsed one
240 256 100       807 $object->bracket = $scope ? '{' : undef;
241            
242             # remove block brackets from scope
243 256 100       558 $scope = substr($scope, 1, -1) if $scope;
244            
245             # parse scope (only if scope was found)
246 256 100       1404 $object->parse($scope) if $object->bracket;
247            
248             # check exit clause
249 256 100       12924 last if $text eq '';
250            
251             }
252             # EO each statement
253            
254             # assert that everything was parsed
255 86 50       206 die "parse error" unless $text eq '';
256            
257             # instance
258 86         183 return $self;
259            
260             }
261             # EO sub parse
262            
263             ####################################################################################################
264            
265             # add some children
266             # ***************************************************************************************
267             sub add
268             {
269            
270             # get input arguments
271 294     294 0 509 my ($self, @children) = @_;
272            
273             # add passed children to our array
274 294         394 push @{$self->{'children'}}, @children;
  294         655  
275            
276             # attach us as parent to all children
277 294         1027 $_->{'parent'} = $self foreach @children;
278            
279             # instance
280 294         641 return $self;
281            
282             }
283             # EO sub add
284            
285             # prepend some children
286             # ***************************************************************************************
287             sub prepend
288             {
289            
290             # get input arguments
291 1     1 0 3 my ($self, @children) = @_;
292            
293             # add passed children to our array
294 1         3 unshift @{$self->{'children'}}, @children;
  1         4  
295            
296             # attach us as parent to all children
297 1         6 $_->{'parent'} = $self foreach @children;
298            
299             # instance
300 1         3 return $self;
301            
302             }
303             # EO sub prepend
304            
305             ####################################################################################################
306            
307             sub body
308             {
309             # get input arguments
310 0     0 0 0 my ($self, $comments, $indent) = @_;
311            
312             # declare string
313 0         0 my $code = '';
314            
315             # init default indent
316 0 0       0 $indent = 0 unless $indent;
317            
318             # render and add each children
319 0         0 foreach my $child (@{$self->children})
  0         0  
320 0         0 { $code .= $child->render($comments, $indent + 1); }
321            
322             # return result
323 0         0 return $code;
324            
325             }
326            
327             # render block with children
328             # return the same css as parsed
329             # ***************************************************************************************
330             sub render
331             {
332            
333             # get input arguments
334 103     103 0 179 my ($self, $comments, $indent) = @_;
335            
336             # declare string
337 103         196 my $code = '';
338            
339             # init default indent
340 103 100       228 $indent = 0 unless $indent;
341            
342             # add code from instance
343 103 100       212 if (defined $self->text)
344 66         130 { $code .= $self->text; }
345            
346             # print to debug the css "dom" tree
347             # print " " x $indent, $self, "\n";
348            
349             # add opener bracket if scope has been set
350 103 100       224 $code .= $opener{$self->bracket} if $self->bracket;
351            
352             # render and add each children
353 103         140 foreach my $child (@{$self->children})
  103         277  
354 70         293 { $code .= $child->render($comments, $indent + 1); }
355            
356             # append some generic footer
357 103         187 $code .= $self->{'footer'};
358            
359             # add closer bracket if scope has been set
360 103 100       179 $code .= $closer{$self->bracket} if $self->bracket;
361            
362             # add object suffix if it has been set
363 103 100       202 $code .= $self->suffix if defined $self->suffix;
364            
365             # return string
366 103         568 return $code;
367            
368             }
369             # EO sub render
370            
371             ####################################################################################################
372             ####################################################################################################
373             1;