File Coverage

blib/lib/Plack/Middleware/Assets/RailsLike/Compiler.pm
Criterion Covered Total %
statement 73 77 94.8
branch 17 18 94.4
condition n/a
subroutine 14 15 93.3
pod 0 2 0.0
total 104 112 92.8


line stmt bran cond sub pod time code
1             package Plack::Middleware::Assets::RailsLike::Compiler;
2              
3 4     4   227411 use strict;
  4         13  
  4         126  
4 4     4   19 use warnings;
  4         9  
  4         117  
5 4     4   17 use Carp ();
  4         9  
  4         72  
6 4     4   3747 use CSS::LESSp ();
  4         23793  
  4         148  
7 4     4   3700 use CSS::Minifier::XS ();
  4         5137  
  4         117  
8 4     4   33 use Errno ();
  4         8  
  4         73  
9 4     4   1119 use File::Slurp;
  4         15370  
  4         394  
10 4     4   1116 use File::Spec::Functions qw(catdir catfile canonpath);
  4         872  
  4         284  
11 4     4   3594 use JavaScript::Minifier::XS ();
  4         3427  
  4         119  
12 4     4   3878 use Text::Sass::XS qw(:const);
  4         18613  
  4         4175  
13              
14             sub new {
15 5     5 0 7761 my $class = shift;
16 5         40 my %args = (
17             minify => 0,
18             search_path => ['.'],
19             @_
20             );
21 5         18 my $self = bless \%args, $class;
22              
23 5         61 $self->{sass_compiler} = Text::Sass::XS->new(
24             output_style => SASS_STYLE_COMPRESSED,
25             source_comments => SASS_SOURCE_COMMENTS_NONE,
26             include_paths => $self->{search_path},
27             image_path => undef, # TBD require option?
28             );
29              
30 5         99 return $self;
31             }
32              
33             sub compile {
34 15     15 0 14863 my $self = shift;
35 15         74 my %args = (
36             manifest => undef,
37             type => 'js',
38             @_
39             );
40              
41 15         32 my $content = $args{manifest};
42              
43 15 100       51 if ( $args{type} eq 'css' ) {
44 9         51 my $css_comment = qr!
45             /\*
46             .*?
47             (?:\r?\n)
48             ((?:\*= .+(?:\r?\n)){1,})
49             \*/
50             !x;
51 9         131 $content =~ s{$css_comment}{$1}g;
52             }
53              
54 15         124 my $parser = qr{
55             ^
56             (?://|\*)=
57             \s+
58             (require) # commands
59             \s+
60             ([0-9a-zA-Z_\-./]+) # basename
61             \s*
62             $
63             }xms;
64              
65 15         138 $content
66 23         62 =~ s/$parser/my $cmd = "_cmd_$1"; $self->$cmd($2, $args{type})/ge;
  23         81  
67              
68 15 100       75 $content = $self->_minify( $content, $args{type} ) if $self->{minify};
69 15         103 return $content;
70             }
71              
72             sub _cmd_require {
73 23     23   30 my $self = shift;
74 23         51 my ( $file, $type ) = @_;
75              
76 23         30 my @search_path = @{ $self->{search_path} };
  23         72  
77 23 100       73 my @type = $type eq 'js' ? qw(js) : qw(css scss sass less);
78              
79 23         45 for my $path (@search_path) {
80 23         30 for my $type (@type) {
81 29         260 my $filename = canonpath(
82             catfile( $path, sprintf( '%s.%s', $file, $type ) ) );
83              
84 29         47 my $buff;
85 29     0   161 read_file( $filename, buf_ref => \$buff, err_mode => sub { } );
  0         0  
86 29 100       3787 unless ($!) {
    50          
87              
88 23         51 my $content;
89 23 100       121 if ( $type eq 'scss' ) {
    100          
    100          
90 1         5 $content = $self->{sass_compiler}->scss2css($buff);
91             }
92             elsif ( $type eq 'sass' ) {
93 1         6 $content = $self->{sass_compiler}->sass2css($buff);
94             }
95             elsif ( $type eq 'less' ) {
96 1         8 $content = join '', CSS::LESSp->parse($buff);
97             }
98             else {
99 20         33 $content = $buff;
100             }
101              
102 23         65993 chomp $content;
103 23         165 return $content;
104             }
105             elsif ( $! == Errno::ENOENT ) {
106 6         11 next;
107             }
108             else {
109 0         0 Carp::carp("read_file '$filename' failed - $!");
110 0         0 return;
111             }
112             }
113             }
114              
115 0         0 Carp::carp( sprintf "requires '%s' failed - No such file in %s",
116             $file, join( ', ', @search_path ) );
117             }
118              
119             sub _minify {
120 6     6   10 my $self = shift;
121 6         11 my ( $content, $type ) = @_;
122 6 100       16 if ( $type eq 'js' ) {
123 3         57 $content = JavaScript::Minifier::XS::minify($content);
124             }
125             else {
126 3         58 $content = CSS::Minifier::XS::minify($content);
127             }
128 6         16 return $content;
129             }
130              
131             1;