handles nested styles of the form C
in reads and writes correctly, making the property available in the
form
$CSS->{'P EM'}->{color}
C ignores comments of the form C* comment */> on read
correctly, however these comments will not be written back out to the
file.
=head1 CSS FILE SYNTAX
Files are written in a relatively human-orientated form, as follows:
H1 {
color: blue;
}
.this {
color: red;
font-size: 10px;
}
P EM {
color: yellow;
}
When reading and writing, all property descriptors, for example C
and C in the example above, are converted to lower case. As an
example, take the following CSS.
P {
Font-Family: Verdana;
}
To get the value C<'Verdana'> from the object C<$CSS>, you should
reference the key C<$CSS-E{P}-E{font-family}>.
=head1 METHODS
=cut
use strict;
BEGIN {
require 5.004;
$CSS::Tiny::VERSION = '1.15';
$CSS::Tiny::errstr = '';
}
=pod
=head2 new
The constructor C creates and returns an empty C object.
=cut
sub new { bless {}, shift }
=pod
=head2 read $filename
The C constructor reads a CSS stylesheet, and returns a new
C object containing the properties in the file.
Returns the object on success, or C on error.
=cut
sub read {
my $class = shift;
# Check the file
my $file = shift or return $class->_error( 'You did not specify a file name' );
return $class->_error( "The file '$file' does not exist" ) unless -e $file;
return $class->_error( "'$file' is a directory, not a file" ) unless -f _;
return $class->_error( "Insufficient permissions to read '$file'" ) unless -r _;
# Read the file
local $/ = undef;
open( CSS, $file ) or return $class->_error( "Failed to open file '$file': $!" );
my $contents = ;
close( CSS );
$class->read_string( $contents )
}
=pod
=head2 read_string $string
The C constructor reads a CSS stylesheet from a string.
Returns the object on success, or C on error.
=cut
sub read_string {
my $self = bless {}, shift;
# Flatten whitespace and remove /* comment */ style comments
my $string = shift;
$string =~ tr/\n\t/ /;
$string =~ s!/\*.*?\*\/!!g;
# Split into styles
foreach ( grep { /\S/ } split /(?<=\})/, $string ) {
unless ( /^\s*([^{]+?)\s*\{(.*)\}\s*$/ ) {
return $self->_error( "Invalid or unexpected style data '$_'" );
}
# Split in such a way as to support grouped styles
my $style = $1;
$style =~ s/\s{2,}/ /g;
my @styles = grep { s/\s+/ /g; 1; } grep { /\S/ } split /\s*,\s*/, $style;
foreach ( @styles ) { $self->{$_} ||= {} }
# Split into properties
foreach ( grep { /\S/ } split /\;/, $2 ) {
unless ( /^\s*([\w._-]+)\s*:\s*(.*?)\s*$/ ) {
return $self->_error( "Invalid or unexpected property '$_' in style '$style'" );
}
foreach ( @styles ) { $self->{$_}->{lc $1} = $2 }
}
}
$self
}
=pod
=head2 clone
The C method creates an identical copy of an existing C
object.
=cut
BEGIN { eval "use Clone 'clone';"; eval <<'END_PERL' if $@; }
sub clone {
my $self = shift;
my $copy = ref($self)->new;
foreach my $key ( keys %$self ) {
my $section = $self->{$key};
$copy->{$key} = {};
foreach ( keys %$section ) {
$copy->{$key}->{$_} = $section->{$_};
}
}
$copy;
}
END_PERL
=pod
=head2 write
The C generates the stylesheet for the properties, and
writes it to disk. Returns true on success. Returns C on error.
=cut
sub write {
my $self = shift;
my $file = shift or return $self->_error( 'No file name provided' );
# Write the file
open( CSS, '>'. $file ) or return $self->_error( "Failed to open file '$file' for writing: $!" );
print CSS $self->write_string;
close( CSS );
1
}
=pod
=head2 write_string
Generates the stylesheet for the object and returns it as a string.
=cut
sub write_string {
my $self = shift;
# Iterate over the styles
# Note: We use 'reverse' in the sort to avoid a special case related
# to A:hover even though the file ends up backwards and looks funny.
# See http://www.w3.org/TR/CSS2/selector.html#dynamic-pseudo-classes
my $contents = '';
foreach my $style ( reverse sort keys %$self ) {
$contents .= "$style {\n";
foreach ( sort keys %{ $self->{$style} } ) {
$contents .= "\t" . lc($_) . ": $self->{$style}->{$_};\n";
}
$contents .= "}\n";
}
$contents
}
=pod
=head2 html
The C method generates the CSS, but wrapped in a C";
}
=pod
=head2 xhtml
The C method generates the CSS, but wrapped in a C";
}
=pod
=head2 errstr
When an error occurs, you can retrieve the error message either from the
C<$CSS::Tiny::errstr> variable, or using the C method.
=cut
sub errstr { $CSS::Tiny::errstr }
sub _error { $CSS::Tiny::errstr = $_[1]; undef }
1;
=pod
=head1 SUPPORT
Bugs should be reported via the CPAN bug tracker at
L
For other issues, or commercial enhancement or support, contact the author.
=head1 AUTHOR
Adam Kennedy Eadamk@cpan.orgE
=head1 SEE ALSO
L, L, L, L
=head1 COPYRIGHT
Copyright 2002 - 2007 Adam Kennedy.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=cut