File Coverage

blib/lib/File/Fu/Base.pm
Criterion Covered Total %
statement 93 131 70.9
branch 24 48 50.0
condition 2 12 16.6
subroutine 27 30 90.0
pod 14 14 100.0
total 160 235 68.0


line stmt bran cond sub pod time code
1             package File::Fu::Base;
2             $VERSION = v0.0.8;
3              
4 13     13   85 use warnings;
  13         23  
  13         484  
5 13     13   65 use strict;
  13         28  
  13         1474  
6 13     13   254 use Carp;
  13         30  
  13         4407  
7              
8 13     13   18032 use File::stat ();
  13         1603340  
  13         3470  
9              
10             =head1 NAME
11              
12             File::Fu::Base - nothing to see here
13              
14             =head1 SYNOPSIS
15              
16             =cut
17              
18             use overload (
19 3     3   383 '=' => sub {shift->clone(@_)},
20 2     2   30 '""' => 'stringify',
21             '%=' => 'append',
22             '%' => sub {shift->clonedo('append', @_)},
23             # can't overload s/// or accomplish anything with prototypes
24 1     1   542 '&' => sub {shift->clonedo('map', @_)},
25 187     187   19072 '&=' => 'map',
26             cmp => sub {"$_[0]" cmp "$_[1]"},
27              
28             # invalid methods
29 1     1   109 '-' => sub {shift->error('-')},
30 1     1   1147 '*' => sub {shift->error('*')},
31 0     0   0 '~' => sub {~ shift->stringify},
32 1     1   631 nomethod => sub {shift->error($_[2])},
33 13     13   130 );
  13         30  
  13         234  
34              
35             =head2 clone
36              
37             my $obj = $obj->clone;
38              
39             =cut
40              
41             sub clone {
42 171     171 1 1309 my $self = shift;
43 171         634 my $clone = {%$self};
44 171         466 bless($clone, ref($self));
45             #carp("clone the ", overload::StrVal($self));
46 171         475 foreach my $item (values(%$clone)) {
47 182 100       633 my $ref = ref($item) or next;
48 171 100       359 if($ref eq 'ARRAY') {
    50          
    50          
49             #warn "clone [@$item]\n";
50 166         605 $item = [@$item];
51             }
52 5         38 elsif($ref eq 'HASH') {
53 0         0 $item = {%$item};
54             }
55             elsif(eval {$item->can('clone')}) {
56 5         15 $item = $item->clone
57             }
58             else {
59 0         0 croak("cannot deref $item");
60             }
61             }
62             #carp("now ", overload::StrVal($clone));
63 171         458 return($clone);
64             } # end subroutine clone definition
65             ########################################################################
66              
67             =head2 clonedo
68              
69             $clone = $self->clonedo($action, @args);
70              
71             =cut
72              
73             sub clonedo {
74 3     3 1 5 my $self = shift;
75 3         6 my ($action, $arg, $rev) = @_;
76             #carp("clonedo $action", $rev ? ' backwards' : '');
77 3 50       8 if($rev) {
78 0 0       0 return($arg . $self->stringify) if($action eq 'append');
79 0         0 croak("$action is invalid in that order");
80             }
81              
82             # perl doesn't know how to stringify
83             # TODO how can I tell when this is just a quoted string?
84             #if($action eq 'append' and $arg =~ m/\n/) { return($self->stringify . $arg); }
85              
86 3         7 $self = $self->clone;
87 3         15 $self->$action($arg);
88             #carp("now ", overload::StrVal($self));
89 3         10 return($self);
90             } # end subroutine clonedo definition
91             ########################################################################
92              
93             =head2 error
94              
95             $package->error($op);
96              
97             =cut
98              
99             sub error {
100 3     3 1 6 my $self = shift;
101 3         5 my ($op) = @_;
102 3         442 croak("$op is not a valid op for a ", ref($self), " object");
103             } # end subroutine error definition
104             ########################################################################
105              
106             =head1 Filetests
107              
108             =head2 r w x o R W X O e z s f d l p S b c t u g k T B M A C
109              
110             See perldoc -f -x
111              
112             =cut
113              
114             foreach my $test (split(//, 'rwxoRWXOezsfdlpSbctugkTBMAC')) {
115 21     21   705 my $subref = eval("sub {-$test shift}");
  0         0  
  0         0  
  7         123  
  1         474  
  2         181  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  2         222  
  0         0  
  0         0  
  0         0  
  0         0  
  1         4  
  1         116  
  8         1324  
  16         8052  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  2         9  
116             $@ and croak("I broke this -- $@");
117 13     13   7954 no strict 'refs';
  13         30  
  13         1135  
118             *{"$test"} = $subref;
119             }
120              
121             =head1 File::Spec stuff
122              
123             This needs to be redone.
124              
125             =cut
126              
127 13     13   74 use File::Spec; # GRR
  13         28  
  13         12559  
128              
129             =head2 is_absolute
130              
131             =cut
132              
133             sub is_absolute {
134             # XXX this is immutable, no?
135 6     6 1 493 File::Spec->file_name_is_absolute($_[0]->stringify);
136             }
137              
138             =head2 relative
139              
140             Get a relative name.
141              
142             my $rel = $abs->relative;
143              
144             Also, with optional relative-to directory:
145              
146             my $rel = $abs->relative($to);
147              
148             =cut
149              
150             sub relative {
151 5     5 1 54 my $self = shift;
152 5         9 my $base = shift;
153 5 100       22 return $self->new(File::Spec->abs2rel($self->stringify,
154             defined($base) ? "$base" : ()
155             ));
156             }
157              
158             =head2 relative_to
159              
160             Same as relative(), but requires the $dir argument.
161              
162             my $rel = $abs->relative_to($dir);
163              
164             =cut
165              
166             sub relative_to {
167 0     0 1 0 my $self = shift;
168 0 0       0 my $base = shift or croak('relative_to() requires a $dir');
169 0         0 return $self->relative($base);
170             }
171              
172             =head2 resolve
173              
174             Fully resolve any symlinks;
175              
176             my $path = $path->resolve;
177              
178             =cut
179              
180             sub resolve {
181 2     2 1 20 my $self = shift;
182 2         4 while(1) {
183 3 100       90 return $self unless($self->l);
184 1         30 my $to = $self->readlink;
185 1 50       12 return $to if($to->is_absolute);
186 1         51 $self = $self->new($self->dirname . $to);
187             }
188             } # end subroutine resolve definition
189             ########################################################################
190              
191             =head2 relative_symlink
192              
193             Where $path and $linkname are both relative to the current directory.
194              
195             $path->relative_symlink($linkname);
196              
197             =cut
198              
199             sub relative_symlink {
200 3     3 1 12 my $self = shift;
201 3         5 my ($link) = @_;
202              
203 3         17 my $rel = $self->relative($self->new($link)->dirname);
204 3         22 return($rel->symlink($link));
205             } # end subroutine relative_symlink definition
206             ########################################################################
207              
208             =head2 utime
209              
210             Update the file timestamps.
211              
212             $file->utime($atime, $mtime);
213              
214             Optionally, set both to the same time.
215              
216             $file->utime($time);
217              
218             Also see touch().
219              
220             =cut
221              
222             sub utime {
223 2     2 1 14 my $self = shift;
224 2 50       7 @_ or croak("not enough arguments to utime()");
225 2         4 my $at = shift;
226 2 50       7 my $mt = @_ ? shift(@_) : $at;
227 2 50       11 if($self->is_dir) {
228 2         7 $self = $self->bare;
229             }
230 2 100       264 utime($at, $mt, $self) or croak("cannot utime '$self' $!");
231             } # end subroutine utime definition
232             ########################################################################
233              
234             =head2 chmod
235              
236             $path->chmod($mode);
237              
238             =cut
239              
240             sub chmod :method {
241 1     1 1 916 my $self = shift;
242 1         5 my ($mode) = @_;
243              
244 1 50       4 chmod($mode, "$self") or croak("cannot chmod '$self' $!");
245             } # end subroutine chmod definition
246             ########################################################################
247              
248             =head2 rename
249              
250             Calls the builtin rename() on the $path and returns a new object with
251             that name.
252              
253             $path = $path->rename($newname);
254              
255             =cut
256              
257             sub rename :method {
258 2     2 1 998 my $self = shift;
259 2         4 my ($name) = @_;
260              
261 2 50       9 rename($self, $name) or
262             croak("cannot rename '$self' to '$name' $!");
263 2         169 return($self->new($name));
264             } # end subroutine rename definition
265             ########################################################################
266              
267             =head1 Stat Object
268              
269             The stat() and lstat() methods both return a File::stat object.
270              
271             =head2 stat
272              
273             my $st = $obj->stat;
274              
275             =cut
276              
277             sub stat {
278 4     4 1 2018 my $self = shift;
279 4 100       17 my $st = File::stat::stat("$self") or
280             croak("cannot stat '$self' $!");
281 3         552 return($st);
282             } # end subroutine stat definition
283             ########################################################################
284              
285             =head2 lstat
286              
287             Same as stat, but does not dereference symlinks.
288              
289             my $st = $obj->lstat;
290              
291             =cut
292              
293             sub lstat {
294 3     3 1 1171 my $self = shift;
295              
296 3 100 66     373 if($self->is_dir and $self->l) {
297 2         11 $self = $self->bare;
298             }
299 3 50       28 my $st = File::stat::lstat("$self") or
300             croak("cannot lstat '$self' $!");
301 3         923 return($st);
302             } # end subroutine lstat definition
303             ########################################################################
304              
305             =head2 is_same
306              
307             Returns true if the two paths are the same. This is by string equality,
308             then (if both paths exist) by device+inode equality.
309              
310             $bool = $path->is_same($other);
311              
312             =cut
313              
314             sub is_same {
315 0     0 1   my $self = shift;
316 0           my ($other) = @_;
317 0 0         unless(ref $other) {
318 0 0 0       my $proto = ($self->is_file and $other =~ m#/$#) ?
319             $self->dir_class : $self;
320 0           $other = $proto->new($other);
321             }
322 0 0         return(1) if($self eq $other);
323 0 0         return(0) if($self->is_dir != $other->is_dir);
324 0           my $n = 0;
325             # TODO just check absolutely?
326             # this currently probably misses non-existent files where the dirname
327             # resolves to the same location.
328 0           my ($s1, $s2) = map({eval {$_->stat}} $self, $other);
  0            
  0            
329 0 0 0       return(0) unless($s1 and $s2);
330             return(
331 0   0       $s1->dev eq $s2->dev and
332             $s1->ino eq $s2->ino
333             );
334             } # end subroutine is_same definition
335             ########################################################################
336              
337             =head1 AUTHOR
338              
339             Eric Wilhelm @
340              
341             http://scratchcomputing.com/
342              
343             =head1 BUGS
344              
345             If you found this module on CPAN, please report any bugs or feature
346             requests through the web interface at L. I will be
347             notified, and then you'll automatically be notified of progress on your
348             bug as I make changes.
349              
350             If you pulled this development version from my /svn/, please contact me
351             directly.
352              
353             =head1 COPYRIGHT
354              
355             Copyright (C) 2008 Eric L. Wilhelm, All Rights Reserved.
356              
357             =head1 NO WARRANTY
358              
359             Absolutely, positively NO WARRANTY, neither express or implied, is
360             offered with this software. You use this software at your own risk. In
361             case of loss, no person or entity owes you anything whatsoever. You
362             have been warned.
363              
364             =head1 LICENSE
365              
366             This program is free software; you can redistribute it and/or modify it
367             under the same terms as Perl itself.
368              
369             =cut
370              
371             # vi:ts=2:sw=2:et:sta
372             1;