File Coverage

blib/lib/Mason/Util.pm
Criterion Covered Total %
statement 129 143 90.2
branch 37 56 66.0
condition 4 6 66.6
subroutine 33 34 97.0
pod 0 19 0.0
total 203 258 78.6


line stmt bran cond sub pod time code
1             package Mason::Util;
2             $Mason::Util::VERSION = '2.23';
3 21     21   18254 use Carp;
  21         33  
  21         1551  
4 21     21   10009 use Class::Unload;
  21         78292  
  21         731  
5 21     21   585 use Class::Load;
  21         21166  
  21         930  
6 21     21   1768 use Data::Dumper;
  21         15316  
  21         1531  
7 21     21   110 use Fcntl qw( :DEFAULT :seek );
  21         25  
  21         7841  
8 21     21   123 use File::Find;
  21         28  
  21         1118  
9 21     21   10906 use File::Spec::Functions ();
  21         14088  
  21         482  
10 21     21   14112 use JSON;
  21         186027  
  21         105  
11 21     21   2944 use Try::Tiny;
  21         48  
  21         1158  
12 21     21   103 use strict;
  21         28  
  21         541  
13 21     21   84 use warnings;
  21         31  
  21         675  
14 21     21   92 use base qw(Exporter);
  21         30  
  21         31136  
15              
16             our @EXPORT_OK =
17             qw(can_load catdir catfile checksum combine_similar_paths dump_one_line find_wanted first_index is_absolute json_encode json_decode mason_canon_path read_file taint_is_on touch_file trim uniq write_file);
18              
19             my $Fetch_Flags = O_RDONLY | O_BINARY;
20             my $Store_Flags = O_WRONLY | O_CREAT | O_BINARY;
21             my $File_Spec_Using_Unix = $File::Spec::ISA[0] eq 'File::Spec::Unix';
22              
23             # Map null, true and false to real Perl values
24             if ( JSON->VERSION < 2 ) {
25             $JSON::UnMapping = 1;
26             }
27              
28             sub can_load {
29              
30             # Load $class_name if possible. Return 1 if successful, 0 if it could not be
31             # found, and rethrow load error (other than not found).
32             #
33 1624     1624 0 2323 my ($class_name) = @_;
34              
35 1624         1984 my $result;
36             try {
37 1624     1624   53548 Class::Load::load_class($class_name);
38 1181         34307 $result = 1;
39             }
40             catch {
41 443 50 33 443   312138 if ( /Can\'t locate .* in \@INC/ && !/Compilation failed/ ) {
42 443         1510 $result = 0;
43             }
44             else {
45 0         0 die $_;
46             }
47 1624         11708 };
48 1624         24378 return $result;
49             }
50              
51             sub catdir {
52 270 50   270 0 2224 return $File_Spec_Using_Unix ? join( "/", @_ ) : File::Spec::Functions::catdir(@_);
53             }
54              
55             sub catfile {
56 270 50   270 0 8144 return $File_Spec_Using_Unix ? join( "/", @_ ) : File::Spec::Functions::catfile(@_);
57             }
58              
59             sub checksum {
60 0     0 0 0 my ($str) = @_;
61              
62             # Adler32 algorithm
63 0         0 my $s1 = 1;
64 0         0 my $s2 = 1;
65 0         0 for my $c ( unpack( "C*", $str ) ) {
66 0         0 $s1 = ( $s1 + $c ) % 65521;
67 0         0 $s2 = ( $s2 + $s1 ) % 65521;
68             }
69 0         0 return ( $s2 << 16 ) + $s1;
70             }
71              
72             # Convert /foo/bar.m, /foo/bar.pm, /foo.m, /foo.pm to
73             # /foo/bar.{m,pm}, /foo.{m,pm}. I have no idea why this takes
74             # so much code.
75             #
76             sub combine_similar_paths {
77 18     18 0 82 my @paths = @_;
78 18         33 my ( @final, $current_base, @current_exts );
79 18         37 foreach my $path (@paths) {
80 220 100       726 if ( my ( $base, $ext ) = ( $path =~ /^(.*)\.(.*)$/ ) ) {
81 211 100 100     624 if ( defined($current_base) && $current_base ne $base ) {
82 91 100       323 push(
83             @final,
84             "$current_base."
85             . (
86             ( @current_exts == 1 )
87             ? $current_exts[0]
88             : sprintf( '{%s}', join( ',', @current_exts ) )
89             )
90             );
91 91         133 @current_exts = ($ext);
92             }
93             else {
94 120         188 push( @current_exts, $ext );
95             }
96 211         266 $current_base = $base;
97             }
98             else {
99 9         16 push( @final, $path );
100             }
101             }
102 18 50       50 if ( defined($current_base) ) {
103 18 100       109 push(
104             @final,
105             "$current_base."
106             . (
107             ( @current_exts == 1 )
108             ? $current_exts[0]
109             : sprintf( '{%s}', join( ',', @current_exts ) )
110             )
111             );
112             }
113 18         145 return @final;
114             }
115              
116             sub delete_package {
117 225     225 0 401 my $pkg = shift;
118 225         1214 Class::Unload->unload($pkg);
119             }
120              
121             sub dump_one_line {
122 13     13 0 22 my ($value) = @_;
123              
124 13         103 return Data::Dumper->new( [$value] )->Indent(0)->Sortkeys(1)->Quotekeys(0)->Terse(1)->Dump();
125             }
126              
127             # From File::Find::Wanted
128             sub find_wanted {
129 6     6 0 7 my $func = shift;
130 6         8 my @files;
131              
132 6         8 local $_;
133 6 100   24   330 find( sub { push @files, $File::Find::name if &$func }, @_ );
  24         44  
134              
135 6         36 return @files;
136             }
137              
138             # From List::MoreUtils
139             sub first_index (&@) {
140 466     466 0 690 my $f = shift;
141 466         1295 for my $i ( 0 .. $#_ ) {
142 881         1414 local *_ = \$_[$i];
143 881 100       1590 return $i if $f->();
144             }
145 419         1428 return -1;
146             }
147              
148             sub is_absolute {
149 1470     1470 0 1616 my ($path) = @_;
150              
151 1470         5670 return substr( $path, 0, 1 ) eq '/';
152             }
153              
154             # Maintain compatibility with both JSON 1 and 2. Borrowed from Data::Serializer::JSON.
155             #
156             sub json_decode {
157 13     13 0 19 my ($text) = @_;
158 13 50       299 return JSON->VERSION < 2 ? JSON->new->jsonToObj($text) : JSON->new->decode($text);
159             }
160              
161             sub json_encode {
162 6     6 0 10 my ($data) = @_;
163 6 50       289 return JSON->VERSION < 2 ? JSON->new->objToJson($data) : JSON->new->utf8->encode($data);
164             }
165              
166             sub mason_canon_path {
167              
168             # Like File::Spec::canonpath but with a few fixes.
169             #
170 1289     1289 0 1486 my $path = shift;
171 1289         5289 $path =~ s|/+|/|g; # xx////yy -> xx/yy
172 1289         2002 $path =~ s|(?:/\.)+/|/|g; # xx/././yy -> xx/yy
173             {
174 1289 50       1284 $path =~ s|^(?:\./)+||s unless $path eq "./"; # ./xx -> xx
  1291         3021  
175 1291         1644 $path =~ s|^/(?:\.\./)+|/|s; # /../../xx -> xx
176 1291 50       2848 $path =~ s|/\Z(?!\n)|| unless $path eq "/"; # xx/ -> xx
177 1291 50       2605 $path =~ s|/[^/]+/\.\.$|| && redo; # /xx/.. -> /
178 1291 100       2828 $path =~ s|[^/]+/\.\./|| && redo; # /xx/../yy -> /yy
179             }
180 1289         2465 return $path;
181             }
182              
183             sub read_file {
184 237     237 0 386 my ($file) = @_;
185              
186             # Fast slurp, adapted from File::Slurp::read, with unnecessary options removed
187             #
188 237         452 my $buf = "";
189 237         1097 my $read_fh;
190 237 50       9791 unless ( sysopen( $read_fh, $file, $Fetch_Flags ) ) {
191 0         0 croak "read_file '$file' - sysopen: $!";
192             }
193 237         1530 my $size_left = -s $read_fh;
194 237         415 while (1) {
195 237         1828 my $read_cnt = sysread( $read_fh, $buf, $size_left, length $buf );
196 237 50       767 if ( defined $read_cnt ) {
197 237 50       760 last if $read_cnt == 0;
198 237         570 $size_left -= $read_cnt;
199 237 50       969 last if $size_left <= 0;
200             }
201             else {
202 0         0 croak "read_file '$file' - sysread: $!";
203             }
204             }
205 237         3238 return $buf;
206             }
207              
208             sub taint_is_on {
209 1036 50   1036 0 5189 return ${^TAINT} ? 1 : 0;
210             }
211              
212             sub touch_file {
213 2     2 0 5 my ($file) = @_;
214 2 50       35 if ( -f $file ) {
215 0         0 my $time = time;
216 0         0 utime( $time, $time, $file );
217             }
218             else {
219 2         7 write_file( $file, "" );
220             }
221             }
222              
223             sub trim {
224 872     872 0 1105 my ($str) = @_;
225 872 100       1731 if ( defined($str) ) {
226 835         1258 for ($str) { s/^\s+//; s/\s+$// }
  835         1582  
  835         5250  
227             }
228 872         9745 return $str;
229             }
230              
231             # From List::MoreUtils
232             sub uniq (@) {
233 1342     1342 0 1646 my %h;
234 1342 100       6179 map { $h{$_}++ == 0 ? $_ : () } @_;
  2009         7800  
235             }
236              
237             sub write_file {
238 524     524 0 1751 my ( $file, $data, $file_create_mode ) = @_;
239              
240 524 50       1266 ($file) = $file =~ /^(.*)/s if taint_is_on(); # Untaint blindly
241 524 50       1427 $file_create_mode = oct(666) if !defined($file_create_mode);
242              
243             # Fast spew, adapted from File::Slurp::write, with unnecessary options removed
244             #
245             {
246 524         681 my $write_fh;
  524         637  
247 524 50       41730 unless ( sysopen( $write_fh, $file, $Store_Flags, $file_create_mode ) ) {
248 0         0 croak "write_file '$file' - sysopen: $!";
249             }
250 524         1446 my $size_left = length($data);
251 524         774 my $offset = 0;
252 524         787 do {
253 524         16508 my $write_cnt = syswrite( $write_fh, $data, $size_left, $offset );
254 524 50       1571 unless ( defined $write_cnt ) {
255 0         0 croak "write_file '$file' - syswrite: $!";
256             }
257 524         910 $size_left -= $write_cnt;
258 524         2018 $offset += $write_cnt;
259             } while ( $size_left > 0 );
260 524         17595 truncate( $write_fh, sysseek( $write_fh, 0, SEEK_CUR ) )
261             }
262             }
263              
264             1;