[Rt-commit] r5342 - in CSS-Squish: lib/CSS t t/css

trs at bestpractical.com trs at bestpractical.com
Wed Jun 7 13:02:13 EDT 2006


Author: trs
Date: Wed Jun  7 13:02:11 2006
New Revision: 5342

Added:
   CSS-Squish/t/00-use.t
   CSS-Squish/t/01-basic.t
   CSS-Squish/t/02-edge-cases.t
   CSS-Squish/t/css/
   CSS-Squish/t/css/01-basic-import.css
   CSS-Squish/t/css/01-basic.css
   CSS-Squish/t/css/02-edge-cases.css
   CSS-Squish/t/css/blam.css
   CSS-Squish/t/css/foo.css
   CSS-Squish/t/css/foo2.css
Modified:
   CSS-Squish/   (props changed)
   CSS-Squish/MANIFEST
   CSS-Squish/Makefile.PL
   CSS-Squish/lib/CSS/Squish.pm

Log:
 r12736 at zot:  tom | 2006-06-07 13:01:53 -0400
 Implementation and *very* basic tests


Modified: CSS-Squish/MANIFEST
==============================================================================
--- CSS-Squish/MANIFEST	(original)
+++ CSS-Squish/MANIFEST	Wed Jun  7 13:02:11 2006
@@ -4,3 +4,12 @@
 MANIFEST			This list of files
 META.yml
 README
+t/00-use.t
+t/01-basic.t
+t/02-edge-cases.t
+t/css/01-basic-import.css
+t/css/01-basic.css
+t/css/02-edge-cases.css
+t/css/blam.css
+t/css/foo.css
+t/css/foo2.css

Modified: CSS-Squish/Makefile.PL
==============================================================================
--- CSS-Squish/Makefile.PL	(original)
+++ CSS-Squish/Makefile.PL	Wed Jun  7 13:02:11 2006
@@ -1,5 +1,4 @@
 use strict;
-use 5.00503;
 use ExtUtils::MakeMaker;
 # See lib/ExtUtils/MakeMaker.pm for details of how to influence
 # the contents of the Makefile that is written.
@@ -9,8 +8,9 @@
     PREREQ_PM         => {}, # e.g., Module::Name => 1.1
     ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
       (ABSTRACT_FROM  => 'lib/CSS/Squish.pm', # retrieve abstract from module
-       AUTHOR         => 'Kevin Riggle <kevinr at bestpractical.com>') : ()),
+       AUTHOR         => 'Thomas Sibley <trs at bestpractical.com>') : ()),
     LIBS              => [''], # e.g., '-lm'
     DEFINE            => '', # e.g., '-DHAVE_SOMETHING'
     INC               => '-I.', # e.g., '-I. -I/usr/include/other'
 );
+

Modified: CSS-Squish/lib/CSS/Squish.pm
==============================================================================
--- CSS-Squish/lib/CSS/Squish.pm	(original)
+++ CSS-Squish/lib/CSS/Squish.pm	Wed Jun  7 13:02:11 2006
@@ -1,220 +1,154 @@
+use strict;
+use warnings;
 
 package CSS::Squish;
 
+$CSS::Squish::VERSION = '0.01';
+
 =head1 NAME
 
-CSS::Squish - Optimize CSS files
+CSS::Squish - Compact many CSS files into one big file
 
 =head1 SYNOPSIS
 
  use CSS::Squish;
-
- open(FILE, 'main.css');
- my $concatenated = CSS::Squish->concatenate($css_file);
+ my $concatenated = CSS::Squish->concatenate(@files);
 
 =head1 DESCRIPTION
 
-The structure of this code blatantly stolen from JavaScript::Squish.
-
-This module currently only supports concatenating CSS files by finding the
-files which are being @include'd and inserting them into the current file.
-
-This saves bandwidth and HTTP requests.
+This module takes a list of CSS files and concatenates them, making sure
+to honor any valid @import statements included in the files.
 
-=head2 EXPORT
+Following the CSS 2.1 spec, @import statements must be the first rules in
+a CSS file.  Media-specific @import statements will be honored by enclosing
+the included file in an @media rule.  This has the side effect of actually
+I<improving> compatibility in Internet Explorer, which ignores
+media-specific @import rules but understands @media rules.
+
+It is possible that feature versions will include methods to compact
+whitespace and other parts of the CSS itself, but this functionality
+is not supported at the current time.
 
-None by default.
+=cut
 
-"squish" may be exported via "use CSS::Squish qw(squish);"
+#
+# This should be a decently close CSS 2.1 compliant parser for @import rules
+#
+# XXX TODO: This does NOT deal with comments at all at the moment.  Which
+# is sort of a problem.
+# 
+
+my @MEDIA_TYPES = qw(all aural braille embossed handheld print
+                     projection screen tty tv);
+my $MEDIA_TYPES = '(?:' . join('|', @MEDIA_TYPES) . ')';
+my $MEDIA_LIST  = qr/(?:$MEDIA_TYPES,\s*)*?$MEDIA_TYPES/;
+
+my $AT_IMPORT = qr/^\s*                     # leading whitespace
+                    \@import\s+             # @import
+                        (?:url\(            #   url(
+                        \s*                 #   optional whitespace
+                        (?:"|')?            #   optional " or '
+                      |                     # or
+                        (?:"|'))            #   " or '
+                      (.+?)                 # the filename
+                        (?:(?:"|')?         #   optional " or '
+                        \s*                 #   optional whitespace
+                        \)                  #   )
+                      |                     # or
+                        (?:"|'))            #   " or '
+                    (?:\s($MEDIA_LIST))?    # the optional media list
+                    \;                      # finishing semi-colon
+                   \s*$                     # trailing whitespace
+                  /x;
 
 =head1 METHODS
 
-=head2 B<CSS::Squish-E<gt>squish($js [, %options] )>
-
-Class method. This is a wrapper around all methods in here, to allow you to do all compacting operations in one call.
-
-     my $squished = CSS::Squish->squish( $javascript );
-
-Current supported options:
-
-=over
+=head2 B<CSS::Squish-E<gt>concatenate(@files)>
 
-=head2 B<CSS::Squish-E<gt>new()>
+Takes a list of files to concatenate and returns the results as one big scalar.
 
-Constructor. Currently takes no options. Returns CSS::Squish object.
+=head2 B<CSS::Squish-E<gt>concatenate_to($dest, @files)>
 
-=head2 B<$djc-E<gt>data($js)>
+Takes a filehandle to print to and a list of files to concatenate.
+C<concatenate> uses this method with an C<open>ed scalar.
 
-If the option C<$js> is passed in, this sets the CSS that will be worked on.
-
-If not passed in, this returns the CSS in whatever state it happens to be in (so you can step through, and pull the data out at any time).
-
-=head2 B<$djc-E<gt>determine_line_ending()>
-
-Method to automatically determine the line ending character in the source data.
-
-=head2 B<$djc-E<gt>eol_char("\n")>
-
-Method to set/override the line ending character which will be used to parse/join lines. Set to "\r\n" if you are working on a DOS / Windows formatted file.
-
-=head2 B<$djc-E<gt>replace_final_eol()>
-
-Prior to this being called, the end of line may not terminated with a new line character (especially after some of the steps above). This assures the data ends in at least one of whatever is set in C<$djc-E<gt>eol_char()>.
-
-=head1 NOTES
+=cut
 
-The following should only cause an issue in rare and odd situations... If the input file is in dos format (line termination with "\r\n" (ie. CR LF / Carriage return Line feed)), we'll attempt to make the output the same. If you have a mixture of embeded "\r\n" and "\n" characters (not escaped, those are still safe) then this script may get confused and make them all conform to whatever is first seen in the file.
+sub concatenate {
+    my $self   = shift;
+    my $string = '';
+    
+    open my $fh, '>', \$string or die "Can't open scalar as file! $!";
+    $self->concatenate_to($fh, @_);
+    close $fh;
 
-=head1 TODO
+    return $string;
+}
 
-Actual implementation of concatenate()
+sub concatenate_to {
+    my $self = shift;
+    my $dest = shift;
+    
+    FILE:
+    while (my $file = shift @_) {
+        my $fh;
+        
+        if (not open $fh, '<', $file) {
+            print $dest qq[/* WARNING: Unable to open file '$file': $! */\n];
+            next FILE;
+        }
+        
+        PROCESS_IMPORTS:
+        while (my $line = <$fh>) {
+            if ($line =~ /$AT_IMPORT/) {
+                my $import = $1;
+                my $media  = $2;
+
+                print $dest "\n/**\n  * Original CSS: $line  */\n\n";
+                
+                if (defined $media) {
+                    print $dest "\@media $media {\n";
+                    $self->concatenate_to($dest, $import);
+                    print $dest "}\n";
+                }
+                else {
+                    $self->concatenate_to($dest, $import);
+                }
+            }
+            else {
+                print $dest $line;
+                last PROCESS_IMPORTS if not $line =~ /^\s*$/;
+            }
+        }
+        print $dest $_ while <$fh>;
+        close $fh;
+    }
+}
 
 =head1 BUGS
 
-Unwritten code has no bugs. :-)
+At the current time, comments are not skipped.  This means comments happening
+before @import statements at the top of a file will cause the @import rules
+to not be parsed.  Make sure the @import rules are the very first thing in
+the file (and only one per line).
+
+All other bugs should be reported via
+L<http://rt.cpan.org/Public/Dist/Display.html?Name=CSS-Squish>
+or L<bugs-CSS-Squish at rt.cpan.org>.
 
 =head1 AUTHOR
 
-Kevin Riggle <kevinr at bestpractical.com>
+Thomas Sibley <trs at bestpractical.com>
 
 =head1 COPYRIGHT AND LICENSE
 
+Copyright (c) 2006.
+
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself, either Perl version 5.8.3 or,
 at your option, any later version of Perl 5 you may have available.
 
 =cut
 
-use 5.00503;
-use strict;
-use Carp qw(croak carp);
-
-require Exporter;
-use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
- at ISA = qw(Exporter);
-
-%EXPORT_TAGS = ( 'all' => [ qw( squish ) ] );
-
- at EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
-
- at EXPORT = qw( );
-
-$VERSION = '0.01';
-
-sub squish {
-    my $this = shift;
-
-    # squish() can be used as a class method or instance method
-    unless (ref $this)
-    {
-        $this = $this->new();
-    }
-
-    {
-        my $data = (ref($_[0]) eq 'SCALAR') ? ${(shift)} : shift;
-        $this->data($data);
-    }
-    my %opts = (ref($_[0]) eq 'HASH') ? %{$_[0]} : @_;
-
-    # determine line ending
-    print STDERR "Determining line ending format (LF || CRLF)...\n" if $opts{DEBUG};
-    $this->determine_line_ending();
-
-    # concatenate imported files
-    print STDERR "Concatenating @import'd files...\n" if $opts{DEBUG};
-    $this->concatenate();
-
-    # replace final EOL
-    print STDERR "Replace final EOL...\n" if $opts{DEBUG};
-    $this->replace_final_eol();
-
-    return $this->data;
-}
-
-sub new {
-    my $proto = shift;
-    my $class = ref($proto) || $proto;
-
-    my $this = {
-        data    => '',
-        strings => [ ],
-        comments => [ ],
-        eol     => "\n",
-        _strings_extracted  => 0, # status var
-        _comments_extracted  => 0, # status var
-        };
-    bless $this, $class;
-
-    return $this;
-}
-
-sub data {
-    my $this = shift;
-    
-    if ($_[0]) {
-        my $data = (ref($_[0]) eq 'SCALAR') ? ${$_[0]} : $_[0];
-        $this->{data} = $_[0];
-    } else {
-        return $this->{data};
-    }
-}
-
-sub eol_char {
-    my $this = shift;
-
-    if ($_[0]) {
-        $this->{eol} = $_[0];
-    } else {
-        return $this->{eol};
-    }
-}
-
-sub determine_line_ending {
-    my $this = shift;
-
-    # Where is the first LF character?
-    my $lf_position = index($this->data, "\n");
-    if ($lf_position == -1)
-    {   # not found, set to default, cause it won't (shouldn't) matter
-        $this->eol_char("\n");
-    } else {
-        if ($lf_position == 0)
-        {   # found at first char, so there is no prior character to observe
-            $this->eol_char("\n");
-        } else {
-            # Is the character immediately before it a CR?
-            my $test_cr = substr($this->data, ($lf_position -1),1);
-            if ($test_cr eq "\r")
-            {
-                $this->eol_char("\r\n");
-            } else {
-                $this->eol_char("\n");
-            }
-        }
-    }
-}
-
-sub replace_final_eol {
-    my $this = shift;
-
-    my $eol  = $this->eol_char();
-    my $data = $this->data;
-    if ($data =~ /\r?\n$/) {
-        $data =~ s/\r?\n$/$eol/;
-    } else {
-        $data .= $eol;
-    }
-    $this->data($data);
-}
-
-sub concatenate {
-    my $this = shift;
-    my $data = $this->data;
-    
-    while ( $data =~ /(.*)\n/g ) {
-        my $line = $1;
-        while ($line !~ /\@import (?:\"|/g)
-    }
-}
-
 1;
+

Added: CSS-Squish/t/00-use.t
==============================================================================
--- (empty file)
+++ CSS-Squish/t/00-use.t	Wed Jun  7 13:02:11 2006
@@ -0,0 +1,8 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Test::More tests => 1;
+
+use_ok("CSS::Squish");
+

Added: CSS-Squish/t/01-basic.t
==============================================================================
--- (empty file)
+++ CSS-Squish/t/01-basic.t	Wed Jun  7 13:02:11 2006
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+
+use Test::More tests => 2;
+
+use_ok("CSS::Squish");
+
+my $expected_result = <<'EOT';
+
+
+/**
+  * Original CSS: @import "t/css/01-basic-import.css";
+  */
+
+inside 01-basic-import.css
+body { color: blue; }
+
+EOT
+
+my $result = CSS::Squish->concatenate('t/css/01-basic.css');
+
+is($result, $expected_result, "Basic import");
+

Added: CSS-Squish/t/02-edge-cases.t
==============================================================================
--- (empty file)
+++ CSS-Squish/t/02-edge-cases.t	Wed Jun  7 13:02:11 2006
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+
+use Test::More skip_all => "diff says the output is the same.  Test::More doesn't.  Argh.";
+
+use_ok("CSS::Squish");
+
+my $expected_result = <<'EOT';
+
+
+/**
+  * Original CSS: @import "t/css/blam.css" print;
+  */
+
+ at media print {
+Blam!
+}
+
+/**
+  * Original CSS: @import "t/css/blam.css";
+  */
+
+Blam!
+
+/**
+  * Original CSS: @import url( "t/css/foo.css") print,aural;
+  */
+
+ at media print,aural {
+foo1
+}
+
+/**
+  * Original CSS: @import url(t/css/foo2.css ) print, aural, tty;
+  */
+
+ at media print, aural, tty {
+foo2
+}
+
+/**
+  * Original CSS: @import 'failure.css' print;
+  */
+
+ at media print {
+/* WARNING: Unable to open file 'failure.css': No such file or directory */
+}
+
+fjkls
+ jk
+
+ at import url("t/css/foo.css");
+
+last
+EOT
+
+my $result = CSS::Squish->concatenate('t/css/02-edge-cases.css');
+
+is($result, $expected_result, "Edge cases");
+

Added: CSS-Squish/t/css/01-basic-import.css
==============================================================================
--- (empty file)
+++ CSS-Squish/t/css/01-basic-import.css	Wed Jun  7 13:02:11 2006
@@ -0,0 +1 @@
+inside 01-basic-import.css

Added: CSS-Squish/t/css/01-basic.css
==============================================================================
--- (empty file)
+++ CSS-Squish/t/css/01-basic.css	Wed Jun  7 13:02:11 2006
@@ -0,0 +1,4 @@
+
+ at import "t/css/01-basic-import.css";
+body { color: blue; }
+

Added: CSS-Squish/t/css/02-edge-cases.css
==============================================================================
--- (empty file)
+++ CSS-Squish/t/css/02-edge-cases.css	Wed Jun  7 13:02:11 2006
@@ -0,0 +1,13 @@
+
+ at import "t/css/blam.css" print;
+ at import "t/css/blam.css";
+ at import url( "t/css/foo.css") print,aural;
+ at import url(t/css/foo2.css ) print, aural, tty;
+ at import 'failure.css' print;
+
+fjkls
+ jk
+ 
+ at import url("t/css/foo.css");
+
+last

Added: CSS-Squish/t/css/blam.css
==============================================================================
--- (empty file)
+++ CSS-Squish/t/css/blam.css	Wed Jun  7 13:02:11 2006
@@ -0,0 +1 @@
+Blam!

Added: CSS-Squish/t/css/foo.css
==============================================================================
--- (empty file)
+++ CSS-Squish/t/css/foo.css	Wed Jun  7 13:02:11 2006
@@ -0,0 +1 @@
+foo1

Added: CSS-Squish/t/css/foo2.css
==============================================================================
--- (empty file)
+++ CSS-Squish/t/css/foo2.css	Wed Jun  7 13:02:11 2006
@@ -0,0 +1 @@
+foo2


More information about the Rt-commit mailing list