File Coverage

lib/File/PathInfo.pm
Criterion Covered Total %
statement 169 192 88.0
branch 87 136 63.9
condition 4 12 33.3
subroutine 25 28 89.2
pod 10 14 71.4
total 295 382 77.2


line stmt bran cond sub pod time code
1             package File::PathInfo;
2 3     3   38803 use Cwd;
  3         6  
  3         242  
3 3     3   17 use Carp;
  3         6  
  3         204  
4 3     3   14 use strict;
  3         7  
  3         78  
5 3     3   12 use warnings;
  3         4  
  3         132  
6             require Exporter;
7 3     3   13 use vars qw(@ISA @EXPORT_OK %EXPORT_TAGS $VERSION $DEBUG);
  3         3  
  3         5355  
8             @ISA = qw(Exporter);
9             @EXPORT_OK = qw(abs_path_n);
10             %EXPORT_TAGS = (
11             all => \@EXPORT_OK,
12             );
13             $VERSION = sprintf "%d.%02d", q$Revision: 1.27 $ =~ /(\d+)/g;
14              
15             $DEBUG =0;
16              
17 1     1 0 13 sub DEBUG : lvalue { $File::PathInfo::DEBUG }
18             $file::PathInfo::RESOLVE_SYMLINKS=1;
19 4     4 0 22 sub RESOLVE_SYMLINKS : lvalue { $File::PathInfo::RESOLVE_SYMLINKS }
20             $File::PathInfo::TIME_FORMAT = 'yyyy/mm/dd hh::mm';
21 0     0 0 0 sub TIME_FORMAT : lvalue { $File::PathInfo::TIME_FORMAT }
22              
23             ___make_get_premethod( '_stat' => qw(is_binary is_dir is_text is_file filesize size ctime
24             atime ctime_pretty atime_pretty mtime_pretty filesize_pretty mtime ino rdev gid uid
25             dev blocks blksize mode nlink));
26              
27             ___make_get_premethod( _abs => qw(abs_path filename abs_loc ext filename_only));
28              
29              
30             sub new {
31 19     19 1 10068 my ($class, $self) = (shift, shift);
32 19   100     139 $self ||= {};
33            
34 19         29 my $arg;
35 19 100       65 unless( ref $self ){
36 10 100       53 print STDERR "arg is not a ref, treating as arg\n" if $DEBUG; # assume to be path argument
37 10         16 $arg = $self;
38 10         21 $self = {};
39             }
40 19         105 bless $self, $class;
41              
42 19 100       58 if ($arg){ $self->set($arg) or Carp::cluck("failed set() $arg") }
  10 100       31  
43            
44 19         84 $self;
45             }
46              
47              
48             sub set {
49 21     21 1 252 my $self= shift;
50 21         77 $self->{_data} = undef;
51 21         44 my $arg = shift;
52 21         53 $self->{_data}->{_argument} = $arg;
53            
54 21 100       51 unless( $self->_abs){
55 8         2669 Carp::cluck("set() '$arg' is not on disk.");
56 8         949 $self->{_data}->{exists} = 0 ;
57 8         794 return 0;
58             }
59 13         63 $self->{_data}->{exists} = 1 ;
60 13         88 $self->abs_path;
61             }
62              
63             sub _argument {
64 21     21   29 my $self = shift;
65 21 50       1336 $self->{_data}->{_argument} or confess("you must call set() before any other methods");
66 21         69 return $self->{_data}->{_argument};
67             }
68              
69              
70             sub _abs {
71 176     176   202 my $self = shift;
72              
73             # croak($self->errstr) if $self->errstr;
74              
75 176 100       379 unless( defined $self->{_data}->{_abs} ){
76              
77 21         100 my $_abs = {
78             abs_loc => undef,
79             filename => undef,
80             abs_path => undef,
81             filename_only => undef,
82             ext => undef,
83             };
84 21         51 $self->{_data}->{_abs} = $_abs;
85            
86 21         1079 my $abs_path;
87 21         49 my $argument = $self->_argument;
88              
89            
90            
91             # IS ARGUMENT ABS PATH ?
92 21 100       150 if ( $argument =~/^\// ) {
    100          
93              
94 4 50       14 if (RESOLVE_SYMLINKS){
95 0         0 $abs_path = Cwd::abs_path($argument);
96             }
97              
98             else {
99 4         18 $abs_path = abs_path_n($argument);
100             }
101            
102 4 50       979 unless($abs_path){
103 0 0       0 print STDERR "argument : '$argument', cant resolve with Cwd::abs_path\n" if $DEBUG;
104 0         0 return ;
105             }
106             }
107              
108              
109              
110             # IS ARG REL TO CWD ?
111             # if starts with dot.. resolve to cwd
112             elsif ( $argument =~/^\.\// ){
113 12 100       31849 unless( $abs_path = Cwd::abs_path(cwd().'/'.$argument) ){
114 1 50       54 print STDERR "argument: '$argument', "
115             ."cant resolve as path rel to current working dir with Cwd abs_path\n" if $DEBUG;
116 1         13 return 0 ;
117             }
118             }
119              
120              
121             # IS ARG REL TO DOC ROOT ?
122             else {
123             ### assume to be rel path then
124 5 50       19 unless( $self->DOCUMENT_ROOT ){
125 0 0 0     0 print STDERR "argument: '$argument'- DOCUMENT_ROOT "
126             ."is not set, needed for an argument starting with a dot\n" if $DEBUG
127             and return 0;
128             }
129            
130 5 50       16 unless( $abs_path = Cwd::abs_path($self->DOCUMENT_ROOT .'/'.$argument) ){
131 0 0       0 print STDERR
132             "argument: '$argument' cant resolve as relative to DOCUMENT ROOT either\n"
133             if $DEBUG;
134 0         0 return 0 ;
135             }
136            
137             }
138              
139              
140              
141              
142             # set main vars
143            
144 20 50       157 $_abs->{abs_path} = $abs_path or return 0;
145              
146 20 100       78 unless (defined $self->{check_exist}){
147 18         58 $self->{check_exist} = 1;
148             }
149 20 50       47 if ($self->{check_exist}){
150 20 100       342 unless( -e $_abs->{abs_path} ){
151 7 100       162 print STDERR "'$$_abs{abs_path}' is not on disk\n" if $DEBUG;
152             #$self->_error( $_abs->{abs_path} ." is not on disk.");
153             ### $abs_path
154             ### is explicitely !-e on disk
155 7         58 return 0;
156             }
157             }
158              
159 13 50       142 $abs_path=~/^(\/.+)\/([^\/]+)$/
160             or die("problem matching abs loc and filename in [$abs_path], ".
161             "argument was [$argument] - maybe you are trying to use a path like /etc,"
162             ."bad juju."); # should not happen
163 13         64 $_abs->{abs_loc} = $1;
164 13         47 $_abs->{filename} = $2;
165 13 100       75 if ($_abs->{filename}=~/^(.+)\.(\w{1,4})$/){
166 9         30 $_abs->{filename_only} =$1;
167 9         21 $_abs->{ext} = $2;
168             }
169             else { #may be a dir
170 4         9 $_abs->{filename_only} = $_abs->{filename};
171             }
172            
173 13         49 $self->{_data}->{_abs} = $_abs;
174             }
175            
176 168         758 $self->{_data}->{_abs};
177             }
178              
179              
180             sub _rel {
181 32     32   39 my $self = shift;
182              
183 32 50       59 croak($self->errstr) if $self->errstr;
184              
185 32 100       70 unless( defined $self->{_data}->{_rel}){
186 12         48 my $_rel = {
187             rel_path => undef,
188             rel_loc => undef,
189             };
190 12         25 $self->{_data}->{_rel} = $_rel;
191 12 50 0     30 $self->DOCUMENT_ROOT or warn('cant use rel methods because DOCUMENT ROOT is not set')
192             and return $_rel;
193            
194 12         32 my $doc_root = $self->DOCUMENT_ROOT;
195 12 50       29 my $abs_path = $self->abs_path or return $_rel;
196              
197 12 50       34 if ($doc_root eq $abs_path){
198 0         0 $_rel->{rel_path} = '';
199 0         0 $_rel->{rel_loc} = '';
200             }
201              
202             else {
203            
204 12 100       25 unless( $self->is_in_DOCUMENT_ROOT ){
205 3 50       12 warn("cant use rel methods because this file [$abs_path] is "
206             ."NOT WITHIN DOCUMENT ROOT:".$self->DOCUMENT_ROOT) if $DEBUG;
207 3         19 return $_rel;
208             }
209            
210 9         15 my $rel_path = $abs_path; # by now if it was the same as document root, should have been detected
211 9 50       79 $rel_path=~s/^$doc_root\/// or croak("abs path [$abs_path] is NOT within DOCUMENT ROOT [$doc_root]");
212            
213 9         20 $_rel->{rel_path} = $rel_path;
214              
215 9 100       38 if ($rel_path=~/^(.+)\/([^\/]+)$/){
216 6         14 my $rel_loc = $1;
217 6         18 my $filename = $2;
218              
219 6 50       15 $filename eq $self->filename or
220             die("filename from abs path not same as filename from init rel regex, why??");
221            
222 6         18 $_rel->{rel_loc} = $1;
223             }
224             else {
225 3         7 $_rel->{rel_loc} = ''; # file is in topmost dir in doc root
226             }
227             }
228              
229 9         21 $self->{_data}->{_rel} = $_rel;
230             }
231            
232 29         92 return $self->{_data}->{_rel};
233             }
234              
235             ___make_get_premethod( _rel => qw(rel_path rel_loc) );
236              
237             sub is_topmost {
238 10     10 1 16 my $self = shift;
239 10 50       18 defined $self->DOCUMENT_ROOT or return 0;
240 10 100       23 $self->abs_loc eq $self->DOCUMENT_ROOT or return 0;
241 3         9 return 1;
242             }
243              
244             sub is_DOCUMENT_ROOT {
245 10     10 1 10 my $self = shift;
246 10 50       16 defined $self->DOCUMENT_ROOT or return 0;
247 10 50       17 $self->abs_path eq $self->DOCUMENT_ROOT or return 0;
248 0         0 return 1;
249             }
250             sub is_in_DOCUMENT_ROOT {
251 31     31 1 41 my $self = shift;
252 31 100       53 $self->exists or return;
253 28         45 my $abs_path = $self->abs_path;
254 28         48 my $document_root = $self->DOCUMENT_ROOT;
255              
256 28 100       240 $abs_path=~/^$document_root\// or return 0; # the trailing slash is imperative
257              
258 26         103 return 1;
259             }
260              
261             sub DOCUMENT_ROOT_set {
262 0     0 1 0 my ($self,$abs)=@_;
263 0 0       0 defined $abs or confess("missing argument");
264 0 0       0 -d $abs or warn("[$abs] not a dir");
265            
266 0         0 $self->{_data}->{DOCUMENT_ROOT} = $abs;
267 0         0 return 1;
268             }
269              
270              
271              
272              
273             sub DOCUMENT_ROOT {
274 116     116 1 117 my $self = shift;
275              
276 116 50       214 croak($self->errstr) if $self->errstr;
277              
278            
279 116 100       231 unless ( defined $self->{_data}->{DOCUMENT_ROOT}){
280            
281 16         17 my $abs_document_root;
282              
283 16 50       75 if( $self->{DOCUMENT_ROOT} ){
    50          
284 0 0 0     0 $abs_document_root = Cwd::abs_path( $self->{DOCUMENT_ROOT} ) or
285             $self->_error(" DOCUMENT_ROOT [$$self{DOCUMENT_ROOT}] does not resolve to disk") and return;
286             }
287              
288             elsif ( $ENV{DOCUMENT_ROOT} ){
289 16 50 0     800 $abs_document_root = Cwd::abs_path( $ENV{DOCUMENT_ROOT} ) or
290             $self->_error(" ENV DOCUMENT_ROOT [$ENV{DOCUMENT_ROOT}] does not resolve to disk") and return;
291             }
292            
293 16         61 $self->{_data}->{DOCUMENT_ROOT} = $abs_document_root;
294             }
295 116         573 return $self->{_data}->{DOCUMENT_ROOT};
296             }
297              
298              
299             # init stat
300             sub _stat {
301 32     32   34 my $self = shift;
302 32 100       41 unless( $self->exists ){
303 3         523 Carp::cluck('File::PathInfo : no file is set(). Use set().');
304 3         391 return {};
305             }
306 29 50       47 croak($self->errstr) if $self->errstr;
307              
308 29 100       47 unless( defined $self->{_data}->{_stat}){
309              
310            
311 4 50       10 my @stat = stat $self->abs_path or die("$! - cant stat ".$self->abs_path);
312              
313 4 50       308 my $data = {
    50          
    100          
    100          
    50          
    50          
314             is_file => -f _ ? 1 : 0,
315             is_dir => -d _ ? 1 : 0,
316             is_binary => -B _ ? 1 : 0,
317             is_text => -T _ ? 1 : 0,
318             is_topmost => $self->is_topmost,
319             is_document_root => $self->DOCUMENT_ROOT ? $self->is_DOCUMENT_ROOT : undef,
320             is_in_document_root => $self->DOCUMENT_ROOT ? $self->is_in_DOCUMENT_ROOT : undef,
321             };
322            
323 4         26 my @keys = qw(dev ino mode nlink uid gid rdev size atime mtime ctime blksize blocks);
324             #map { $data->{ shift @keys } = $_ } @stat;
325 4         11 for (@stat) {
326 52         38 my $v= $_;
327 52         47 my $key = shift @keys;
328 52         84 $data->{$key} = $v;
329             }
330            
331 4         32 $data->{ filesize_pretty } = ( sprintf "%d",($data->{size} / 1024 )).'k';
332              
333 4         1392 require Time::Format;
334 4         4086 for my $v (qw(ctime atime mtime)){
335 12         25076 $data->{$v.'_pretty'} = Time::Format::time_format($self->_time_format, $data->{$v} );
336             }
337            
338 4         526 $data->{ filesize } = $data->{size};
339            
340 4         15 $self->{_data}->{_stat} = $data;
341             }
342              
343 29         84 return $self->{_data}->{_stat};
344             }
345              
346             sub _time_format {
347 12     12   16 my $self = shift;
348 12   100     88 $self->{time_format} ||= 'yyyy/mm/dd hh:mm';
349 12         257 return $self->{time_format};
350             }
351              
352              
353             # this is to replace
354             # all these :
355             # sub is_binary {
356             # my $self = shift;
357             # return $self->_stat->{is_binary};
358             # }
359             sub ___make_get_premethod {
360 9     9   25 my $method_data = shift;
361 3     3   25 no strict 'refs';
  3         17  
  3         1210  
362 9         13 for my $method_name ( @_ ){
363 87     154   157 *{"File\:\:PathInfo\:\:$method_name"} = sub { return $_[0]->$method_data->{$method_name} };
  87         226  
  154         3494  
364             }
365 9         11 return;
366             }
367              
368              
369             sub get_datahash {
370 4     4 1 1171 my $data = {};
371 4         14 for my $method ( qw(_abs _rel _stat) ){
372 12         13 KEY: while( my ($k,$v) = each %{$_[0]->$method} ){
  65         120  
373 53 100       93 defined $v or next KEY;
374 35         65 $data->{$k} =$v;
375             }
376             }
377 4         23 $data;
378             }
379              
380 0     0   0 sub _error { $_[0]->{_data}->{_errors}.="File::Info, $_[1]\n" }
381             sub errstr {
382 178     178 1 582 my $self = shift;
383 178 100       280 ($self->{_data}->{_errors} = $_[0]) if $_[0];
384 178         351 $self->{_data}->{_errors}
385             }
386              
387             sub exists {
388 66     66 0 78 my $self = shift;
389 66 50       137 defined $self->{_data}->{exists} or confess('must call set() first');
390 66         153 $self->{_data}->{exists};
391             }
392              
393              
394             # NON OO
395              
396             sub abs_path_n {
397 4     4 1 7 my $absPath = shift;
398 4 50       14 return $absPath if $absPath =~ m{^/$};
399 4         22 my @elems = split m{/}, $absPath;
400 4         9 my $ptr = 1;
401 4         17 while($ptr <= $#elems)
402             {
403 11 50       46 if($elems[$ptr] eq q{})
    50          
    50          
404             {
405 0         0 splice @elems, $ptr, 1;
406             }
407             elsif($elems[$ptr] eq q{.})
408             {
409 0         0 splice @elems, $ptr, 1;
410             }
411             elsif($elems[$ptr] eq q{..})
412             {
413 0 0       0 if($ptr < 2)
414             {
415 0         0 splice @elems, $ptr, 1;
416             }
417             else
418             {
419 0         0 $ptr--;
420 0         0 splice @elems, $ptr, 2;
421             }
422             }
423             else
424             {
425 11         26 $ptr++;
426             }
427             }
428 4 50       48 return $#elems ? join q{/}, @elems : q{/};
429              
430             # by JohnGG
431             # http://perlmonks.org/?node_id=603442
432             }
433              
434              
435              
436              
437             1;
438              
439             # see lib/File/PathInfo.pod