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.24';
3 21     21   19541 use Carp;
  21         54  
  21         1573  
4 21     21   9918 use Class::Unload;
  21         78236  
  21         720  
5 21     21   576 use Class::Load;
  21         22374  
  21         930  
6 21     21   1216 use Data::Dumper;
  21         11072  
  21         1038  
7 21     21   96 use Fcntl qw( :DEFAULT :seek );
  21         26  
  21         7595  
8 21     21   111 use File::Find;
  21         25  
  21         1073  
9 21     21   10705 use File::Spec::Functions ();
  21         13577  
  21         442  
10 21     21   13857 use JSON;
  21         177738  
  21         101  
11 21     21   2985 use Try::Tiny;
  21         35  
  21         1207  
12 21     21   113 use strict;
  21         35  
  21         550  
13 21     21   95 use warnings;
  21         35  
  21         727  
14 21     21   87 use base qw(Exporter);
  21         29  
  21         32543  
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 2688 my ($class_name) = @_;
34              
35 1624         2593 my $result;
36             try {
37 1624     1624   63472 Class::Load::load_class($class_name);
38 1181         43430 $result = 1;
39             }
40             catch {
41 443 50 33 443   285788 if ( /Can\'t locate .* in \@INC/ && !/Compilation failed/ ) {
42 443         1393 $result = 0;
43             }
44             else {
45 0         0 die $_;
46             }
47 1624         13601 };
48 1624         28538 return $result;
49             }
50              
51             sub catdir {
52 270 50   270 0 2441 return $File_Spec_Using_Unix ? join( "/", @_ ) : File::Spec::Functions::catdir(@_);
53             }
54              
55             sub catfile {
56 270 50   270 0 8484 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 140 my @paths = @_;
78 18         32 my ( @final, $current_base, @current_exts );
79 18         56 foreach my $path (@paths) {
80 220 100       1033 if ( my ( $base, $ext ) = ( $path =~ /^(.*)\.(.*)$/ ) ) {
81 211 100 100     860 if ( defined($current_base) && $current_base ne $base ) {
82 91 100       639 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         203 @current_exts = ($ext);
92             }
93             else {
94 120         195 push( @current_exts, $ext );
95             }
96 211         336 $current_base = $base;
97             }
98             else {
99 9         18 push( @final, $path );
100             }
101             }
102 18 50       73 if ( defined($current_base) ) {
103 18 100       182 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         150 return @final;
114             }
115              
116             sub delete_package {
117 225     225 0 418 my $pkg = shift;
118 225         1395 Class::Unload->unload($pkg);
119             }
120              
121             sub dump_one_line {
122 13     13 0 17 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         7 my @files;
131              
132 6         6 local $_;
133 6 100   24   328 find( sub { push @files, $File::Find::name if &$func }, @_ );
  24         42  
134              
135 6         35 return @files;
136             }
137              
138             # From List::MoreUtils
139             sub first_index (&@) {
140 466     466 0 691 my $f = shift;
141 466         1318 for my $i ( 0 .. $#_ ) {
142 881         1489 local *_ = \$_[$i];
143 881 100       1629 return $i if $f->();
144             }
145 419         1497 return -1;
146             }
147              
148             sub is_absolute {
149 1470     1470 0 1599 my ($path) = @_;
150              
151 1470         6199 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 22 my ($text) = @_;
158 13 50       280 return JSON->VERSION < 2 ? JSON->new->jsonToObj($text) : JSON->new->decode($text);
159             }
160              
161             sub json_encode {
162 6     6 0 57 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 1763 my $path = shift;
171 1289         6568 $path =~ s|/+|/|g; # xx////yy -> xx/yy
172 1289         2095 $path =~ s|(?:/\.)+/|/|g; # xx/././yy -> xx/yy
173             {
174 1289 50       1221 $path =~ s|^(?:\./)+||s unless $path eq "./"; # ./xx -> xx
  1291         3135  
175 1291         1637 $path =~ s|^/(?:\.\./)+|/|s; # /../../xx -> xx
176 1291 50       2734 $path =~ s|/\Z(?!\n)|| unless $path eq "/"; # xx/ -> xx
177 1291 50       2845 $path =~ s|/[^/]+/\.\.$|| && redo; # /xx/.. -> /
178 1291 100       2846 $path =~ s|[^/]+/\.\./|| && redo; # /xx/../yy -> /yy
179             }
180 1289         3101 return $path;
181             }
182              
183             sub read_file {
184 237     237 0 408 my ($file) = @_;
185              
186             # Fast slurp, adapted from File::Slurp::read, with unnecessary options removed
187             #
188 237         972 my $buf = "";
189 237         343 my $read_fh;
190 237 50       12233 unless ( sysopen( $read_fh, $file, $Fetch_Flags ) ) {
191 0         0 croak "read_file '$file' - sysopen: $!";
192             }
193 237         1437 my $size_left = -s $read_fh;
194 237         397 while (1) {
195 237         2232 my $read_cnt = sysread( $read_fh, $buf, $size_left, length $buf );
196 237 50       775 if ( defined $read_cnt ) {
197 237 50       830 last if $read_cnt == 0;
198 237         541 $size_left -= $read_cnt;
199 237 50       1029 last if $size_left <= 0;
200             }
201             else {
202 0         0 croak "read_file '$file' - sysread: $!";
203             }
204             }
205 237         8085 return $buf;
206             }
207              
208             sub taint_is_on {
209 1036 50   1036 0 5202 return ${^TAINT} ? 1 : 0;
210             }
211              
212             sub touch_file {
213 2     2 0 5 my ($file) = @_;
214 2 50       66 if ( -f $file ) {
215 0         0 my $time = time;
216 0         0 utime( $time, $time, $file );
217             }
218             else {
219 2         8 write_file( $file, "" );
220             }
221             }
222              
223             sub trim {
224 872     872 0 1202 my ($str) = @_;
225 872 100       1643 if ( defined($str) ) {
226 835         1309 for ($str) { s/^\s+//; s/\s+$// }
  835         1582  
  835         5342  
227             }
228 872         11237 return $str;
229             }
230              
231             # From List::MoreUtils
232             sub uniq (@) {
233 1342     1342 0 2166 my %h;
234 1342 100       2948 map { $h{$_}++ == 0 ? $_ : () } @_;
  2009         10134  
235             }
236              
237             sub write_file {
238 524     524 0 1755 my ( $file, $data, $file_create_mode ) = @_;
239              
240 524 50       1275 ($file) = $file =~ /^(.*)/s if taint_is_on(); # Untaint blindly
241 524 50       1466 $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         639 my $write_fh;
  524         747  
247 524 50       47390 unless ( sysopen( $write_fh, $file, $Store_Flags, $file_create_mode ) ) {
248 0         0 croak "write_file '$file' - sysopen: $!";
249             }
250 524         1568 my $size_left = length($data);
251 524         800 my $offset = 0;
252 524         985 do {
253 524         17902 my $write_cnt = syswrite( $write_fh, $data, $size_left, $offset );
254 524 50       1752 unless ( defined $write_cnt ) {
255 0         0 croak "write_file '$file' - syswrite: $!";
256             }
257 524         1038 $size_left -= $write_cnt;
258 524         2018 $offset += $write_cnt;
259             } while ( $size_left > 0 );
260 524         22624 truncate( $write_fh, sysseek( $write_fh, 0, SEEK_CUR ) )
261             }
262             }
263              
264             1;