line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
2
|
|
|
|
|
|
|
## CSS Object Oriented - ~/lib/CSS/Object.pm |
3
|
|
|
|
|
|
|
## Version v0.1.5 |
4
|
|
|
|
|
|
|
## Copyright(c) 2021 DEGUEST Pte. Ltd. |
5
|
|
|
|
|
|
|
## Author: Jacques Deguest <jack@deguest.jp> |
6
|
|
|
|
|
|
|
## Created 2020/06/24 |
7
|
|
|
|
|
|
|
## Modified 2021/11/28 |
8
|
|
|
|
|
|
|
## All rights reserved |
9
|
|
|
|
|
|
|
## |
10
|
|
|
|
|
|
|
## This program is free software; you can redistribute it and/or modify it |
11
|
|
|
|
|
|
|
## under the same terms as Perl itself. |
12
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
13
|
|
|
|
|
|
|
package CSS::Object; |
14
|
|
|
|
|
|
|
BEGIN |
15
|
|
|
|
|
|
|
{ |
16
|
6
|
|
|
6
|
|
221028
|
use strict; |
|
6
|
|
|
|
|
25
|
|
|
6
|
|
|
|
|
194
|
|
17
|
6
|
|
|
6
|
|
30
|
use warnings; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
177
|
|
18
|
6
|
|
|
6
|
|
30
|
use warnings::register; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
757
|
|
19
|
6
|
|
|
6
|
|
2774
|
use parent qw( Module::Generic ); |
|
6
|
|
|
|
|
2019
|
|
|
6
|
|
|
|
|
33
|
|
20
|
6
|
|
|
6
|
|
151540942
|
use CSS::Object::Builder; |
|
6
|
|
|
|
|
21
|
|
|
6
|
|
|
|
|
96
|
|
21
|
6
|
|
|
6
|
|
4391
|
use CSS::Object::Comment; |
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
69
|
|
22
|
6
|
|
|
6
|
|
1364
|
use CSS::Object::Format; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
37
|
|
23
|
6
|
|
|
6
|
|
3885
|
use CSS::Object::Property; |
|
6
|
|
|
|
|
26
|
|
|
6
|
|
|
|
|
87
|
|
24
|
6
|
|
|
6
|
|
1547
|
use CSS::Object::Rule; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
65
|
|
25
|
6
|
|
|
6
|
|
4132
|
use CSS::Object::Rule::At; |
|
6
|
|
|
|
|
19
|
|
|
6
|
|
|
|
|
92
|
|
26
|
6
|
|
|
6
|
|
3993
|
use CSS::Object::Rule::Keyframes; |
|
6
|
|
|
|
|
27
|
|
|
6
|
|
|
|
|
81
|
|
27
|
6
|
|
|
6
|
|
4000
|
use CSS::Object::Selector; |
|
6
|
|
|
|
|
17
|
|
|
6
|
|
|
|
|
79
|
|
28
|
6
|
|
|
6
|
|
1429
|
use CSS::Object::Value; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
53
|
|
29
|
6
|
|
|
6
|
|
1338
|
use Want (); |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
114
|
|
30
|
6
|
|
|
6
|
|
31
|
use Devel::Confess; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
31
|
|
31
|
6
|
|
|
6
|
|
12818
|
our $VERSION = 'v0.1.5'; |
32
|
|
|
|
|
|
|
}; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub init |
35
|
|
|
|
|
|
|
{ |
36
|
6
|
|
|
6
|
1
|
5823
|
my $self = shift( @_ ); |
37
|
6
|
|
|
|
|
368
|
$self->{parser} = 'CSS::Object::Parser::Default'; |
38
|
6
|
|
|
|
|
20
|
$self->{format} = ''; |
39
|
6
|
|
|
|
|
19
|
$self->{_init_strict_use_sub} = 1; |
40
|
6
|
50
|
|
|
|
48
|
$self->SUPER::init( @_ ) || return( $self->pass_error ); |
41
|
|
|
|
|
|
|
# $self->message( 3, "Formatter class set: '", ref( $self->format ), "'." ); |
42
|
6
|
100
|
|
|
|
514
|
unless( $self->_is_a( $self->{format}, 'CSS::Object::Format' ) ) |
43
|
|
|
|
|
|
|
{ |
44
|
3
|
|
|
|
|
42
|
my $format = CSS::Object::Format->new( |
45
|
|
|
|
|
|
|
debug => $self->debug |
46
|
|
|
|
|
|
|
); |
47
|
3
|
|
|
|
|
26
|
$self->format( $format ); |
48
|
|
|
|
|
|
|
} |
49
|
6
|
|
|
|
|
86
|
$self->{rules} = Module::Generic::Array->new; |
50
|
6
|
|
|
|
|
72
|
return( $self ); |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# Add comment at the top level. To add comment inside a rule, see add_element in CSS::Object::Rule |
54
|
|
|
|
|
|
|
sub add_element |
55
|
|
|
|
|
|
|
{ |
56
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
57
|
1
|
|
50
|
|
|
4
|
my $elem = shift( @_ ) || return( $self->error( "No element object was provided to add to this rule." ) ); |
58
|
1
|
50
|
|
|
|
73
|
return( $self->error( "Element object provided ($elem) is not a CSS::Object::Element object." ) ) if( !$self->_is_a( $elem, 'CSS::Object::Element' ) ); |
59
|
|
|
|
|
|
|
# $self->message( 3, "Adding element object '$elem'." ); |
60
|
|
|
|
|
|
|
# $elem->format( $self->format ); |
61
|
1
|
|
|
|
|
20
|
$elem->debug( $self->debug ); |
62
|
|
|
|
|
|
|
# $self->properties->push( $prop ); |
63
|
1
|
|
|
|
|
38
|
$self->elements->push( $elem ); |
64
|
1
|
|
|
|
|
47
|
return( $self ); |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub add_rule |
68
|
|
|
|
|
|
|
{ |
69
|
9
|
|
|
9
|
1
|
27
|
my $self = shift( @_ ); |
70
|
9
|
|
|
|
|
21
|
my $rule = shift( @_ ); |
71
|
9
|
|
|
|
|
59
|
$self->message( 4, "CSS rule provided to add to our stack of elements: '", overload::StrVal( $rule ), "'." ); |
72
|
9
|
50
|
|
|
|
283
|
return( $self->error( "No rule object was provided to add." ) ) if( !defined( $rule ) ); |
73
|
9
|
50
|
|
|
|
34
|
return( $self->error( "Object provided is not a CSS::Object::Rule object." ) ) if( !$self->_is_a( $rule, 'CSS::Object::Rule' ) ); |
74
|
|
|
|
|
|
|
# $self->rules->push( $rule ); |
75
|
9
|
|
|
|
|
176
|
$self->elements->push( $rule ); |
76
|
9
|
|
|
|
|
412
|
$self->message( 4, "Returning rule object added: '", overload::StrVal( $rule ), "'. Now we have ", $self->elements->length, " rules stored." ); |
77
|
9
|
|
|
|
|
464291
|
return( $rule ); |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
sub as_string |
81
|
|
|
|
|
|
|
{ |
82
|
2
|
|
|
2
|
1
|
1042
|
my $self = shift( @_ ); |
83
|
2
|
|
|
|
|
50
|
$self->messagef( 3, "There are %d elements in our stack.", $self->elements->length ); |
84
|
2
|
50
|
|
|
|
103003
|
if( @_ ) |
85
|
|
|
|
|
|
|
{ |
86
|
0
|
|
|
|
|
0
|
my $format = shift( @_ ); |
87
|
0
|
0
|
0
|
|
|
0
|
return( $self->error( "Provided parameter to as_string was not an CSS::Object::Format object." ) ) if( $format !~ /^CSS\::Object\::Format/ && !$self->_is_a( $format, 'CSS::Object::Format' ) ); |
88
|
|
|
|
|
|
|
$self->elements->foreach(sub |
89
|
|
|
|
|
|
|
{ |
90
|
0
|
|
|
0
|
|
0
|
shift->format( $format ); |
91
|
0
|
|
|
|
|
0
|
}); |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
2
|
|
|
|
|
18
|
my $output = Module::Generic::Array->new; |
95
|
|
|
|
|
|
|
# $self->rules->foreach(sub |
96
|
|
|
|
|
|
|
$self->elements->foreach(sub |
97
|
|
|
|
|
|
|
{ |
98
|
4
|
|
|
4
|
|
333
|
$output->push( shift->as_string ); |
99
|
2
|
|
|
|
|
30
|
}); |
100
|
2
|
|
|
|
|
159
|
my $nl = $self->format->new_line; |
101
|
2
|
|
|
|
|
89
|
return( $output->join( "$nl$nl" )->scalar ); |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub builder |
105
|
|
|
|
|
|
|
{ |
106
|
1
|
|
|
1
|
1
|
407
|
my $self = shift( @_ ); |
107
|
1
|
50
|
|
|
|
6
|
return( $self->{_builder} ) if( $self->_is_object( $self->{_builder} ) ); |
108
|
|
|
|
|
|
|
# $self->message( 3, "Creating builder object with debug set to '", $self->debug, "' and formatter set to '", $self->format->class, "'." ); |
109
|
1
|
|
50
|
|
|
16
|
my $b = CSS::Object::Builder->new( $self, debug => $self->debug ) || |
110
|
|
|
|
|
|
|
return( $self->error( "Could not initialise the CSS builder: ", CSS::Object::Builder->error ) ); |
111
|
1
|
|
|
|
|
10
|
$self->{_builder} = $b; |
112
|
1
|
|
|
|
|
3
|
return( $b ); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
1
|
|
|
1
|
1
|
29
|
sub charset { return( shift->_set_get_scalar_as_object( 'charset', @_ ) ); } |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# Array of CSS::Object::Element objects or their sub classes |
118
|
35
|
|
|
35
|
1
|
213
|
sub elements { return( shift->_set_get_object_array_object( 'elements', 'CSS::Object::Element', @_ ) ); } |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub format |
121
|
|
|
|
|
|
|
{ |
122
|
132
|
|
|
132
|
1
|
2195
|
my $self = shift( @_ ); |
123
|
132
|
100
|
|
|
|
434
|
if( @_ ) |
124
|
|
|
|
|
|
|
{ |
125
|
6
|
|
|
|
|
14
|
my $val = shift( @_ ); |
126
|
6
|
|
|
|
|
14
|
my $format; |
127
|
6
|
100
|
33
|
|
|
45
|
if( ref( $val ) ) |
|
|
50
|
|
|
|
|
|
128
|
|
|
|
|
|
|
{ |
129
|
3
|
|
50
|
|
|
24
|
$format = $self->_set_get_object( 'format', 'CSS::Object::Format', $val ) || return( $self->pass_error ); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
# Formatter as a class name |
132
|
|
|
|
|
|
|
elsif( !ref( $val ) && CORE::index( $val, '::' ) != -1 ) |
133
|
|
|
|
|
|
|
{ |
134
|
3
|
50
|
|
|
|
23
|
$self->_load_class( $val ) || return( $self->pass_error ); |
135
|
3
|
|
50
|
|
|
426
|
$format = $val->new( debug => $self->debug ) || return( $self->pass_error( $val->error ) ); |
136
|
3
|
|
|
|
|
41
|
$self->_set_get_object( 'format', 'CSS::Object::Format', $format ); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
else |
139
|
|
|
|
|
|
|
{ |
140
|
0
|
|
|
|
|
0
|
return( $self->error( "Unknown format \"$val\". I do not know what to do with it." ) ); |
141
|
|
|
|
|
|
|
} |
142
|
6
|
|
|
0
|
|
268
|
$self->messagef( 3, "Setting new formatter '$format' for %d elements -> %s", $self->elements->length, sub{ $self->elements->join( "', '" )} ); |
|
0
|
|
|
|
|
0
|
|
143
|
|
|
|
|
|
|
$self->elements->foreach(sub |
144
|
|
|
|
|
|
|
{ |
145
|
0
|
0
|
|
0
|
|
0
|
return(1) if( !$self->_is_object( $_[0] ) ); |
146
|
0
|
0
|
|
|
|
0
|
shift->format( $format ) || return; |
147
|
6
|
|
|
|
|
342598
|
}); |
148
|
6
|
|
|
|
|
647
|
return( $format ); |
149
|
|
|
|
|
|
|
} |
150
|
126
|
|
|
|
|
409
|
return( $self->_set_get_object( 'format', 'CSS::Object::Format' ) ); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub get_rule_by_selector |
154
|
|
|
|
|
|
|
{ |
155
|
1
|
|
|
1
|
1
|
594
|
my( $self, $name ) = @_; |
156
|
1
|
50
|
|
|
|
5
|
return( $self->error( "No selector was provided to find its equivalent rule object." ) ) if( !$name ); |
157
|
|
|
|
|
|
|
# $self->messagef( 3, "%d elements found.", $self->elements->length ); |
158
|
1
|
|
|
|
|
5
|
my $found = Module::Generic::Array->new; |
159
|
1
|
|
|
|
|
10
|
foreach my $rule ( @{$self->elements} ) |
|
1
|
|
|
|
|
4
|
|
160
|
|
|
|
|
|
|
{ |
161
|
3
|
50
|
|
|
|
131
|
next if( !$rule->isa( 'CSS::Object::Rule' ) ); |
162
|
|
|
|
|
|
|
# $self->messagef( 3, "This rule has %d selectors", $rule->selectors->length ); |
163
|
3
|
|
|
|
|
5
|
foreach my $sel ( @{$rule->selectors} ) |
|
3
|
|
|
|
|
12
|
|
164
|
|
|
|
|
|
|
{ |
165
|
|
|
|
|
|
|
# $self->message( 3, "Does '", $sel->name, "' match our target selector '$name' ?" ); |
166
|
5
|
100
|
|
|
|
240
|
if( $sel->name eq $name ) |
167
|
|
|
|
|
|
|
{ |
168
|
|
|
|
|
|
|
# return( $rule ); |
169
|
1
|
|
|
|
|
73
|
$found->push( $rule ); |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
## The user is calling this in a chain context, we make sure this is possible using the Module::Generic::Null class if needed |
174
|
1
|
50
|
|
|
|
51
|
if( Want::want( 'OBJECT' ) ) |
|
|
50
|
|
|
|
|
|
175
|
|
|
|
|
|
|
{ |
176
|
0
|
0
|
|
|
|
0
|
rreturn( $found->length > 0 ? $found->first : Module::Generic::Null->new ); |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
elsif( Want::want( 'LIST' ) ) |
179
|
|
|
|
|
|
|
{ |
180
|
0
|
|
|
|
|
0
|
rreturn( @$found ); |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
else |
183
|
|
|
|
|
|
|
{ |
184
|
1
|
|
|
|
|
104
|
return( $found->first ); |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub load_parser |
189
|
|
|
|
|
|
|
{ |
190
|
5
|
|
|
5
|
1
|
14
|
my $self = shift( @_ ); |
191
|
5
|
|
|
|
|
26
|
my $parser_class = $self->parser; |
192
|
5
|
50
|
|
|
|
299
|
$self->_load_class( "$parser_class" ) || return( $self->error( "Unable to load parser class \"$parser_class\": ", $self->error ) ); |
193
|
5
|
|
50
|
|
|
926
|
my $parser = $parser_class->scalar->new( $self ) || return( $self->error( "Unable to instantiate parser \"$parser_class\" object: ", $parser_class->scalar->error ) ); |
194
|
5
|
|
|
|
|
57
|
$parser->debug( $self->debug ); |
195
|
|
|
|
|
|
|
# $self->message( 3, "Parser \"$parser_class\" initiated with object '$parser'." ); |
196
|
5
|
|
|
|
|
222
|
return( $parser ); |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub new_at_rule |
200
|
|
|
|
|
|
|
{ |
201
|
0
|
|
|
0
|
0
|
0
|
my $self = shift( @_ ); |
202
|
0
|
|
|
|
|
0
|
my $o = CSS::Object::Rule::At->new( @_, |
203
|
|
|
|
|
|
|
format => $self->format, |
204
|
|
|
|
|
|
|
debug => $self->debug, |
205
|
|
|
|
|
|
|
css => $self, |
206
|
|
|
|
|
|
|
); |
207
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Cannot create a new at rule object: ", CSS::Object::Rule::At->error ) ) if( !defined( $o ) ); |
208
|
0
|
|
|
|
|
0
|
return( $o ); |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub new_keyframes_rule |
212
|
|
|
|
|
|
|
{ |
213
|
1
|
|
|
1
|
0
|
22
|
my $self = shift( @_ ); |
214
|
1
|
|
|
|
|
4
|
my $o = CSS::Object::Rule::Keyframes->new( @_, |
215
|
|
|
|
|
|
|
format => $self->format, |
216
|
|
|
|
|
|
|
debug => $self->debug, |
217
|
|
|
|
|
|
|
css => $self, |
218
|
|
|
|
|
|
|
); |
219
|
1
|
50
|
|
|
|
9
|
return( $self->error( "Cannot create a new keyframes rule object: ", CSS::Object::Rule::Keyframes->error ) ) if( !defined( $o ) ); |
220
|
1
|
|
|
|
|
5
|
return( $o ); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub new_comment |
224
|
|
|
|
|
|
|
{ |
225
|
5
|
|
|
5
|
1
|
54
|
my $self = shift( @_ ); |
226
|
5
|
|
|
|
|
30
|
my $o = CSS::Object::Comment->new( @_, format => $self->format, debug => $self->debug ); |
227
|
5
|
50
|
|
|
|
50
|
return( $self->error( "Cannot create a new comment object: ", CSS::Object::Comment->error ) ) if( !defined( $o ) ); |
228
|
5
|
|
|
|
|
29
|
return( $o ); |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub new_property |
232
|
|
|
|
|
|
|
{ |
233
|
15
|
|
|
15
|
1
|
493
|
my $self = shift( @_ ); |
234
|
15
|
|
|
|
|
80
|
my $o = CSS::Object::Property->new( @_, format => $self->format, debug => $self->debug ); |
235
|
15
|
50
|
|
|
|
140
|
return( $self->error( "Cannot create a new property object: ", CSS::Object::Property->error ) ) if( !defined( $o ) ); |
236
|
15
|
|
|
|
|
79
|
return( $o ); |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub new_rule |
240
|
|
|
|
|
|
|
{ |
241
|
26
|
|
|
26
|
1
|
923
|
my $self = shift( @_ ); |
242
|
26
|
|
|
|
|
152
|
$self->message( 3, "Creating new rule with formatter '", $self->format->class, "'." ); |
243
|
26
|
|
|
|
|
636
|
my $o = CSS::Object::Rule->new( @_, format => $self->format, debug => $self->debug ); |
244
|
26
|
50
|
|
|
|
222
|
return( $self->error( "Cannot create a new rule object: ", CSS::Object::Rule->error ) ) if( !defined( $o ) ); |
245
|
|
|
|
|
|
|
# $self->message( 3, "Returning \"", overload::StrVal( $o ), "\"." ); |
246
|
26
|
|
|
|
|
147
|
return( $o ); |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub new_selector |
250
|
|
|
|
|
|
|
{ |
251
|
47
|
|
|
47
|
1
|
857
|
my $self = shift( @_ ); |
252
|
47
|
|
|
|
|
189
|
my $o = CSS::Object::Selector->new( @_, format => $self->format, debug => $self->debug ); |
253
|
47
|
50
|
|
|
|
362
|
return( $self->error( "Cannot create a new selector object: ", CSS::Object::Selector->error ) ) if( !defined( $o ) ); |
254
|
47
|
|
|
|
|
224
|
return( $o ); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub new_value |
258
|
|
|
|
|
|
|
{ |
259
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
260
|
0
|
|
|
|
|
0
|
my $o = CSS::Object::Value->new( @_, format => $self->format, debug => $self->debug ); |
261
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Cannot create a new value object: ", CSS::Object::Value->error ) ) if( !defined( $o ) ); |
262
|
0
|
|
|
|
|
0
|
return( $o ); |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub parse_string |
266
|
|
|
|
|
|
|
{ |
267
|
5
|
|
|
5
|
1
|
15
|
my $self = shift( @_ ); |
268
|
5
|
|
|
|
|
17
|
my $string = shift( @_ ); |
269
|
5
|
|
|
|
|
34
|
$self->message( 3, "Parsing string '$string'" ); |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# remove comments |
272
|
|
|
|
|
|
|
# $string =~ s!/\*.*?\*\/!!g; |
273
|
5
|
|
|
|
|
107
|
$string =~ s|<!--||g; |
274
|
5
|
|
|
|
|
21
|
$string =~ s|-->||g; |
275
|
|
|
|
|
|
|
|
276
|
5
|
|
50
|
|
|
26
|
my $parser = $self->load_parser || return( $self->pass_error ); |
277
|
5
|
|
50
|
|
|
26
|
my $elems = $parser->parse_string( $string ) || return( $self->pass_error( $parser->error ) ); |
278
|
5
|
|
|
|
|
30
|
$self->messagef( 3, "Parser returned %d elements.", $elems->length ); |
279
|
5
|
|
|
|
|
288059
|
$self->messagef( 3, "First element is of class \"", ref( $elems->first ), "\"." ); |
280
|
|
|
|
|
|
|
# $self->messagef( 3, "First rule has %d properties.", $rules->first->properties->length ); |
281
|
5
|
|
|
|
|
983
|
return( $elems ); |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
6
|
|
|
6
|
1
|
281
|
sub parser { return( shift->_set_get_scalar_as_object( 'parser', @_ ) ); } |
285
|
|
|
|
|
|
|
|
286
|
2
|
|
|
2
|
1
|
59163
|
sub purge { return( shift->elements->reset ); } |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
sub read_file |
289
|
|
|
|
|
|
|
{ |
290
|
5
|
|
|
5
|
1
|
61585
|
my $self = shift( @_ ); |
291
|
5
|
|
|
|
|
15
|
my $path = shift( @_ ); |
292
|
|
|
|
|
|
|
|
293
|
5
|
50
|
|
|
|
41
|
if( ref( $path ) ) |
|
|
50
|
|
|
|
|
|
294
|
|
|
|
|
|
|
{ |
295
|
0
|
0
|
|
|
|
0
|
if( ref( $path ) eq 'ARRAY' ) |
296
|
|
|
|
|
|
|
{ |
297
|
0
|
|
|
|
|
0
|
$self->read_file( $_ ) for( @$path ); |
298
|
0
|
|
|
|
|
0
|
return( $self ); |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
elsif( $path ) |
302
|
|
|
|
|
|
|
{ |
303
|
5
|
|
|
|
|
56
|
$self->message( 3, "Reading file \"$path\"." ); |
304
|
5
|
|
50
|
|
|
186
|
my $io = IO::File->new( "<$path" ) || return( $self->error( "Could not open file \"$path\": $!" ) ); |
305
|
5
|
|
|
|
|
859
|
$io->binmode( ':utf8' ); |
306
|
5
|
|
|
|
|
459
|
my $source = join( '', $io->getlines ); |
307
|
5
|
|
|
|
|
66
|
$io->close; |
308
|
5
|
|
|
|
|
162
|
$self->messagef( 3, "%d bytes of data read.", CORE::length( $source ) ); |
309
|
5
|
50
|
|
|
|
152
|
if( $source ) |
310
|
|
|
|
|
|
|
{ |
311
|
5
|
|
50
|
|
|
30
|
my $elems = $self->parse_string( $source ) || return( $self->pass_error ); |
312
|
5
|
|
|
|
|
34
|
$self->messagef( 3, "%d elements found from parsing.", $elems->length ); |
313
|
|
|
|
|
|
|
# $self->rules->push( @$rules ); |
314
|
5
|
|
|
|
|
290588
|
$self->elements->push( @$elems ); |
315
|
|
|
|
|
|
|
} |
316
|
5
|
|
|
|
|
438
|
return( $self ); |
317
|
|
|
|
|
|
|
} |
318
|
0
|
|
|
|
|
0
|
return( $self->error( "Only scalars and arrays accepted: $!" ) ); |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
sub read_string |
322
|
|
|
|
|
|
|
{ |
323
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
324
|
0
|
|
|
|
|
0
|
my $data = shift( @_ ); |
325
|
|
|
|
|
|
|
|
326
|
0
|
0
|
|
|
|
0
|
if( ref( $data ) ) |
|
|
0
|
|
|
|
|
|
327
|
|
|
|
|
|
|
{ |
328
|
0
|
0
|
|
|
|
0
|
if( ref( $data ) eq 'ARRAY' ) |
329
|
|
|
|
|
|
|
{ |
330
|
0
|
|
|
|
|
0
|
for( @$data ) |
331
|
|
|
|
|
|
|
{ |
332
|
0
|
0
|
|
|
|
0
|
$self->read_string( $_ ) || return( $self->pass_error ); |
333
|
|
|
|
|
|
|
} |
334
|
0
|
|
|
|
|
0
|
return( $self ); |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
elsif( length( $data ) ) |
338
|
|
|
|
|
|
|
{ |
339
|
0
|
|
0
|
|
|
0
|
my $elems = $self->parse_string( $data ) || return( $self->pass_error ); |
340
|
|
|
|
|
|
|
## $self->rules->push( @$rules ); |
341
|
0
|
|
|
|
|
0
|
$self->elements->push( @$elems ); |
342
|
|
|
|
|
|
|
} |
343
|
0
|
|
|
|
|
0
|
return( $self ); |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
sub remove_rule |
347
|
|
|
|
|
|
|
{ |
348
|
0
|
|
|
0
|
0
|
0
|
my $self = shift( @_ ); |
349
|
0
|
|
|
|
|
0
|
my $rule = shift( @_ ); |
350
|
|
|
|
|
|
|
# $self->message( 3, "CSS rule provided to add to our stack of elements: '", overload::StrVal( $rule ), "'." ); |
351
|
0
|
0
|
|
|
|
0
|
return( $self->error( "No rule object was provided to remove." ) ) if( !defined( $rule ) ); |
352
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Object provided is not a CSS::Object::Rule object." ) ) if( !$self->_is_a( $rule, 'CSS::Object::Rule' ) ); |
353
|
0
|
|
|
|
|
0
|
$self->elements->remove( $rule ); |
354
|
0
|
|
|
|
|
0
|
return( $self ); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# sub rules { return( shift->_set_get_array_as_object( 'rules', @_ ) ); } |
358
|
27
|
50
|
|
27
|
1
|
762
|
sub rules { return( $_[0]->elements->map(sub{ $_[0]->_is_a( $_, 'CSS::Object::Rule' ) ? $_ : () }) ); } |
|
6
|
|
|
6
|
|
121115
|
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
1; |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
# XXX POD |
363
|
|
|
|
|
|
|
__END__ |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=encoding utf-8 |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=head1 NAME |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
CSS::Object - CSS Object Oriented |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=head1 SYNOPSIS |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
use CSS::Object; |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head1 VERSION |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
v0.1.5 |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=head1 DESCRIPTION |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
L<CSS::Object> is a object oriented CSS parser and manipulation interface. |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head2 new |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
To instantiate a new L<CSS::Object> object, pass an hash reference of following parameters: |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=over 4 |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=item I<debug> |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
This is an integer. The bigger it is and the more verbose is the output. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=item I<format> |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
This is a L<CSS::Object::Format> object or one of its child modules. |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=item I<parser> |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
This is a L<CSS::Object::Parser> object or one of its child modules. |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=back |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=head1 EXCEPTION HANDLING |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
Whenever an error has occurred, L<CSS::Object> will set a L<Module::Generic::Exception> object containing the detail of the error and return undef. |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
The error object can be retrieved with the inherited L<Module::Generic/error> method. For example: |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
my $css = CSS::Object->new( debug => 3 ) || die( CSS::Object->error ); |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=head1 METHODS |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=head2 add_element |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
Provided with a L<CSS::Object::Element> object and this adds it to the list of css elements. |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
It uses an array object L</elements> which is an L<Module::Generic::Array> object. |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=head2 add_rule |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
Provided with a L<CSS::Object::Rule> object and this adds it to our list of rules. It returns the rule object that was added. |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
=head2 as_string |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
This will return the css data structure, currently registered, as a string. |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
It takes an optional L<CSS::Object::Format> object as a parameter, to control the output. If none are provided, it will use the default one calling L</format> |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=head2 builder |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
This returns a new L<CSS::Object::Builder> object. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=head2 charset |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
This sets or gets the css charset. It stores the value in a L<Module::Generic::Scalar> object. |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
=head2 elements |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
Sets or gets the array of CSS elements. This is a L<Module::Generic::Array> object that accepts only L<CSS::Object::Element> objects or its child classes, such as L<CSS::Object::Rule>, L<CSS::Object::Comment>, etc |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
=head2 format |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
Sets or gets a L<CSS::Object::Format> object. See L</as_string> below for more detail about their use. |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
L<CSS::Object::Format> objects control the stringification of the css structure. By default, it will return the data in a string identical or at least very similar to the one parsed if it was parsed. |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head2 get_rule_by_selector |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
Provided with a selector and this returns a L<CSS::Object::Rule> object or an empty string. |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
Hoever, if this method is called in an object context, such as chaining, then it returns a L<Module::Generic::Null> object instead of an empty string to prevent the perl error of C<xxx method called on an undefined value>. For example: |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
$css->get_rule_by_selector( '.does-not-exists' )->add_element( $elem ) || |
456
|
|
|
|
|
|
|
die( "Unable to add css element to rule \".does-not-exists\": ", $css->error ); |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
But, in a non-object context, such as: |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
my $rule = $css->get_rule_by_selector( '.does-not-exists' ) || |
461
|
|
|
|
|
|
|
die( "Unable to add css element to rule \".does-not-exists\": ", $css->error ); |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
L</get_rule_by_selector> will return an empty value. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=head2 load_parser |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
This will instantiate a new object based on the parser name specified with L</parser> or during css object instantiation. |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
It returns a new L<CSS::Object::Parser> object, or one of its child module matching the L</parser> specified. |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=head2 new_comment |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
This returns a new L<CSS::Object::Comment> object and pass its instantiation method the provided arguments. |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
return( $css->new_comment( $array_ref_of_comment_ilnes ) ); |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=head2 new_property |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
This takes a property name, and an optional value o array of values and return a new L<CSS::Object::Property> object |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=head2 new_rule |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
This returns a new L<CSS::Object::Rule> object. |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=head2 new_selector |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
This takes a selector name and returns a new L<CSS::Object::Selector> object. |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
=head2 new_value |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
This takes a property value and returns a new L<CSS::Object::Value> object. |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=head2 parse_string |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
Provided with some css data and this will instantiate the L</parser>, call L<CSS::Object::Parser/parse_string> and returns an array of L<CSS::Object::Rule> objects. The array is an array object from L<Module::Generic::Array> and can be used as a regular array or as an object. |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=head2 parser |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
Sets or gets the L<CSS::Object::Parser> object to be used by L</parse_string> to parse css data. |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
A valid parser object can be from L<CSS::Object::Parser> or any of its sub modules. |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
It returns the current parser object. |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
=head2 purge |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
This empties the array containing all the L<CSS::Object::Rule> objects. |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=head2 read_file |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
Provided with a css file, and this will load it into memory and parse it using the parser name registered with L</parser>. |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
It can also take an array reference of css files who will be each fed to L</read_file> |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
It returns the L<CSS::Object> used to call this method. |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
=head2 read_string |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
Provided with some css data, and this will call L</parse_string>. It also accepts an array reference of data. |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
It returns the css object used to call this method. |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=head2 rules |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
This sets or gets the L<Module::Generic::Array> object used to store all the L<CSS::Object::Rule> objects. |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=head1 AUTHOR |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=head1 SEE ALSO |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
L<CSS::Object> |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
L<Mozilla documentation on Custom CSS Properties|https://developer.mozilla.org/en-US/docs/Web/CSS/--*> |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
Copyright (c) 2020 DEGUEST Pte. Ltd. |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
You can use, copy, modify and redistribute this package and associated |
542
|
|
|
|
|
|
|
files under the same terms as Perl itself. |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=cut |