File Coverage

lib/Path/Extended/Entity.pm
Criterion Covered Total %
statement 126 140 90.0
branch 45 58 77.5
condition 18 24 75.0
subroutine 37 40 92.5
pod 19 19 100.0
total 245 281 87.1


line stmt bran cond sub pod time code
1             package Path::Extended::Entity;
2              
3 28     28   78021 use strict;
  28         273  
  28         942  
4 28     28   139 use warnings;
  28         46  
  28         728  
5 28     28   134 use Carp ();
  28         59  
  28         610  
6 28     28   151 use File::Spec;
  28         46  
  28         648  
7 28     28   24966 use Log::Dump;
  28         71320  
  28         170  
8 28     28   9146 use Scalar::Util qw( blessed );
  28         60  
  28         3790  
9              
10             use overload
11 224     224   7300 '""' => sub { shift->path },
12 53     53   181 'cmp' => sub { return "$_[0]" cmp "$_[1]" },
13 964     964   2840 'bool' => sub { shift->_boolify },
14 28     28   55182 '*{}' => sub { shift->_handle };
  28     150   33429  
  28         424  
  150         304  
15              
16             sub new {
17 504     504 1 24115 my $class = shift;
18 504         1494 my $self = bless {}, $class;
19              
20 504 100       2018 $self->_initialize(@_) or return;
21              
22 503         1485 $self;
23             }
24              
25 4     4   15 sub _initialize {1}
26 964     964   2272 sub _boolify {1}
27              
28             sub _class {
29 318     318   953 my ($self, $type) = @_;
30 318         542 my $class = ref $self;
31 318         1772 $class =~ s/::(?:File|Dir|Entity)$//;
32 318 100       791 return $class unless $type;
33 310 100       1278 return $class.'::'.($type eq 'file' ? 'File' : 'Dir');
34             }
35              
36             sub _set_path {
37 499     499   795 my ($self, $path) = @_;
38 499         1214 $self->{input_path} = $self->_unixify($path);
39 499         5786 $self->{abs_path} = $self->_unixify( File::Spec->rel2abs($path) );
40              
41             # respect setting of _attribute when already done
42 499   100     23654 $self->{_stringify_absolute} ||= File::Spec->file_name_is_absolute($path);
43             }
44              
45             sub _related {
46 299     299   725 my ($self, $type, @parts) = @_;
47              
48 299         883 my $class = $self->_class($type);
49 299 50       18220 eval "require $class" or Carp::croak $@;
50 299         749 my $item;
51 299 100 66     2805 if ( @parts && $parts[0] eq '..' ) { # parent
    100 66        
52 101         407 require File::Basename;
53 101         384 $item = $class->new( File::Basename::dirname($self->_absolute) );
54             }
55             elsif ( @parts && File::Spec->file_name_is_absolute($parts[0]) ) {
56 10         41 $item = $class->new( @parts );
57             }
58             else {
59 188         558 $item = $class->new( $self->_absolute, @parts );
60             }
61 299         702 foreach my $key ( grep /^_/, keys %{ $self } ) {
  299         1850  
62 390         1147 $item->{$key} = $self->{$key};
63             }
64 299         1383 $item;
65             }
66              
67             sub _unixify {
68 2280     2280   3303 my ($self, $path) = @_;
69              
70 2280 50       6627 $path =~ s{\\}{/}g if $^O eq 'MSWin32';
71              
72 2280         74416 return $path;
73             }
74              
75 182     182   1616 sub _handle { shift->{handle} }
76              
77             sub _stringify_absolute {
78 300     300   341 my $self = shift;
79 300 100 100     2567 $self->{_stringify_absolute} && !$self->{_base} ? 1 : '';
80             }
81              
82             # returns the string version of the path
83             sub path {
84 300     300 1 380 my $self = shift;
85 300 100       714 return ( $self->_stringify_absolute ) ? $self->_absolute : $self->_relative;
86             }
87              
88 27     27 1 60 sub stringify { shift->path }
89              
90 103     103 1 369 sub is_dir { shift->{is_dir} }
91 457 100   457 1 2947 sub is_open { shift->{handle} ? 1 : 0 }
92              
93              
94             sub is_absolute {
95 8     8 1 37 my $self = shift;
96 8         70 File::Spec->file_name_is_absolute($self->{input_path});
97             }
98              
99             sub resolve {
100 2     2 1 8 my $self = shift;
101 2 50       106 Carp::croak "$self: $!" unless -e $self->{abs_path};
102             # WoP :
103             # Cwd::realpath returns the resolved absolute path
104             # calling File::Spec->file_name_is_absolute() not necessary
105 2         96 $self->{abs_path} = $self->_unixify(Cwd::realpath($self->{abs_path}));
106 2         21 $self->{_stringify_absolute} = File::Spec->file_name_is_absolute($self->{abs_path});
107 2         12818 $self;
108             }
109              
110             sub _absolute {
111 1128     1128   3281 my ($self, %options) = @_;
112              
113 1128         4818 my $path = File::Spec->canonpath( $self->{abs_path} );
114 1128 50       3711 if ( $options{native} ) {
    100          
115 0         0 return $path;
116             }
117             elsif ( $self->{_compat} ) {
118 265         4109 my ($vol, @parts) = File::Spec->splitpath( $path );
119 265 50       753 $vol = '' if $Path::Extended::IgnoreVolume;
120 265         3312 return $self->_unixify( File::Spec->catpath($vol, File::Spec->catdir( @parts ), '') );
121             }
122             else {
123 863         1764 return $self->_unixify($path);
124             }
125             }
126              
127             sub _relative {
128 152     152   231 my $self = shift;
129 152 100       369 my $base = @_ % 2 ? shift : undef;
130 152         243 my %options = @_;
131              
132 152   100     676 $base ||= $options{base} || $self->{_base};
      100        
133              
134 152         10043 my $path = File::Spec->abs2rel( $self->{abs_path}, $base );
135 152 50       593 $path = $self->_unixify($path) unless $options{native};
136              
137 152         554496 $path;
138             }
139              
140 41     41 1 183 sub absolute { shift->_absolute(@_) }
141 62     62 1 202 sub relative { shift->_relative(@_) }
142              
143 97     97 1 1040 sub parent { shift->_related( dir => '..' ); }
144              
145             sub unlink {
146 33     33 1 3336 my $self = shift;
147              
148 33 100       90 $self->close if $self->is_open;
149 33 100       119 unlink $self->_absolute if $self->exists;
150             }
151              
152             sub exists {
153 238     238 1 537 my $self = shift;
154              
155 238 100       591 -e $self->_absolute ? 1 : 0;
156             }
157              
158             sub is_writable {
159 0     0 1 0 my $self = shift;
160              
161 0 0       0 -w $self->_absolute ? 1 : 0;
162             }
163              
164             sub is_readable {
165 0     0 1 0 my $self = shift;
166              
167 0 0       0 -r $self->_absolute ? 1 : 0;
168             }
169              
170             sub copy_to {
171 4     4 1 40 my ($self, $destination) = @_;
172              
173 4 100       12 unless ( $destination ) {
174 1         10 $self->log( fatal => 'requires destination' );
175 1         23 return;
176             }
177              
178 3         7 my $class = ref $self;
179 3         15 $destination = $class->new( "$destination" );
180              
181 3         2043 require File::Copy::Recursive;
182             File::Copy::Recursive::rcopy( $self->_absolute, $destination->_absolute )
183 3 50       22332 or do { $self->log( error => "Can't copy $self to $destination: $!" ); return; };
  0         0  
  0         0  
184              
185 3         2901 $self;
186             }
187              
188             sub move_to {
189 4     4 1 20 my ($self, $destination) = @_;
190              
191 4 100       13 unless ( $destination ) {
192 1         4 $self->log( fatal => 'requires destination' );
193 1         17 return;
194             }
195              
196 3         6 my $class = ref $self;
197 3         16 $destination = $class->new( "$destination" );
198              
199 3 100       10 $self->close if $self->is_open;
200              
201 3         30 require File::Copy::Recursive;
202             File::Copy::Recursive::rmove( $self->_absolute, $destination->_absolute )
203 3 50       13 or do { $self->log( error => "Can't move $self to $destination: $!" ); return; };
  0         0  
  0         0  
204              
205 3         3033 $self->{abs_path} = $destination->_absolute;
206              
207 3         13 $self;
208             }
209              
210             sub rename_to {
211 4     4 1 22 my ($self, $destination) = @_;
212              
213 4 100       14 unless ( $destination ) {
214 1         5 $self->log( fatal => 'requires destination' );
215 1         13 return;
216             }
217              
218 3         40 my $class = ref $self;
219 3         19 $destination = $class->new( "$destination" );
220              
221 3 100       10 $self->close if $self->is_open;
222              
223             rename $self->_absolute => $destination->_absolute
224 3 50       11 or do { $self->log( error => "Can't rename $self to $destination: $!" ); return; };
  0         0  
  0         0  
225              
226 3         13 $self->{abs_path} = $destination->_absolute;
227              
228 3         13 $self;
229             }
230              
231             sub stat {
232 6     6 1 492 my $self = shift;
233              
234 6         2816 require File::stat;
235 6   66     22641 File::stat::stat( $self->{handle} || $self->{abs_path} );
236             }
237              
238             sub lstat {
239 0     0 1   my $self = shift;
240              
241 0           require File::stat;
242 0   0       File::stat::lstat( $self->{handle} || $self->{abs_path} );
243             }
244              
245             1;
246              
247             __END__