File Coverage

blib/lib/File/Fu/Dir.pm
Criterion Covered Total %
statement 264 279 94.6
branch 71 104 68.2
condition 16 18 88.8
subroutine 62 64 96.8
pod 38 38 100.0
total 451 503 89.6


line stmt bran cond sub pod time code
1             package File::Fu::Dir;
2             $VERSION = v0.0.8;
3              
4 13     13   739 use warnings;
  13         29  
  13         490  
5 13     13   68 use strict;
  13         25  
  13         477  
6 13     13   67 use Carp;
  13         25  
  13         921  
7              
8 13     13   83 use Cwd ();
  13         28  
  13         187  
9              
10 13     13   70 use File::Path (); # for now
  13         28  
  13         193  
11              
12 13     13   8318 use File::Fu::Dir::Temp;
  13         42  
  13         444  
13 13     13   141 use File::Fu::File::Temp;
  13         25  
  13         345  
14              
15             =head1 NAME
16              
17             File::Fu::Dir - a directoryname object
18              
19             =head1 SYNOPSIS
20              
21             use File::Fu;
22              
23             my $dir = File::Fu->dir("path/to/dir");
24             $dir->e and warn "$dir exists";
25              
26             $dir->l and warn "$dir is a link to ", $dir->readlink;
27              
28             foreach my $entry ($dir->list) {
29             warn $entry . ': ' . $entry->stat->size, "\n"
30             if($entry->f);
31             }
32              
33             =cut
34              
35 13     13   91 use base 'File::Fu::Base';
  13         24  
  13         1314  
36              
37             use overload (
38 13         79 '+' => 'file',
39             '/' => 'subdir',
40 13     13   72 );
  13         24  
41              
42             =head1 Constructor
43              
44             =head2 new
45              
46             my $dir = File::Fu::Dir->new($path);
47              
48             my $dir = File::Fu::Dir->new(@path);
49              
50             =cut
51              
52             sub new {
53 216     216 1 1144 my $package = shift;
54 216   66     911 my $class = ref($package) || $package;
55 216         588 my $self = {$class->_init(@_)};
56 216         573 bless($self, $class);
57 216         1707 return($self);
58             } # end subroutine new definition
59             ########################################################################
60              
61             =head1 Class Constants/Methods
62              
63             =head2 file_class
64              
65             Return the corresponding file class for this dir object. Default:
66             L.
67              
68             my $fc = $class->file_class;
69              
70             =head2 is_dir
71              
72             Always true for a directory.
73              
74             =head2 is_file
75              
76             Always false for a directory.
77              
78             =cut
79              
80 13     13   2476 use constant top_class => 'File::Fu';
  13         27  
  13         805  
81 13     13   66 use constant file_class => 'File::Fu::File';
  13         27  
  13         646  
82 13     13   66 use constant token_class => 'File::Fu::Dir::Token';
  13         25  
  13         1197  
83 13     13   65 use constant is_dir => 1;
  13         21  
  13         988  
84 13     13   63 use constant is_file => 0;
  13         24  
  13         63011  
85              
86             ########################################################################
87              
88             =head2 temp_dir_class
89              
90             Class for L objects. Default: L.
91              
92             my $class = File::Fu::Dir->temp_dir_class;
93              
94             =cut
95              
96             sub temp_dir_class {
97 3     3 1 6 my $package = shift;
98 3         12 my $class = ref($package) . '::Temp';
99 3 50       77 $class = __PACKAGE__ . '::Temp' unless($class->can('new'));
100 3         26 return($class);
101             } # end subroutine temp_dir_class definition
102             ########################################################################
103              
104             =head2 temp_file_class
105              
106             my $class = File::Fu::Dir->temp_file_class;
107              
108             =cut
109              
110             sub temp_file_class {
111 4     4 1 8 my $package = shift;
112 4         17 my $class = $package->file_class . '::Temp';
113 4 50       48 $class = __PACKAGE__->file_class.'::Temp' unless($class->can('new'));
114 4         32 return($class);
115             } # end subroutine temp_file_class definition
116             ########################################################################
117              
118             =for internal head2 _init
119             my %fields = $class->_init(@_);
120              
121             =cut
122              
123             sub _init {
124 390     390   544 my $class = shift;
125 390 100       1130 @_ or return(dirs => ['.']);
126 302 100       1765 my $dirs = [map({
127 289         473 $_ eq '' ? ('') : split(/\/+/, $_)
128             } @_)];
129 289 100       885 @$dirs or $dirs = ['']; # XXX
130 289         985 return(dirs => $dirs);
131             } # end subroutine _init definition
132             ########################################################################
133              
134             =head1 Methods
135              
136             =head2 stringify
137              
138             my $string = $dir->stringify;
139              
140             =cut
141              
142             sub stringify {
143 662     662 1 2473 my $self = shift;
144             #Carp::carp("stringify", overload::StrVal($self));
145             #defined($self->{dirs}) or croak("how did this happen?");
146 662         755 my @dirs = @{$self->{dirs}};
  662         3331  
147             #warn "I'm (", join(',', @{$self->{dirs}}), ")";
148 662 50       1573 @dirs or return('/');
149             # TODO volume
150 662         20052 join('/', @dirs, ''); # always a trailing slash
151             } # end subroutine stringify definition
152             ########################################################################
153              
154             =begin shutup_pod_cover
155              
156             =head2 l
157              
158             =end shutup_pod_cover
159              
160             =cut
161              
162 32     32   1420 *l = sub {-l shift->bare};
163              
164             =head2 bare
165              
166             Stringify without the trailing slash/assertion.
167              
168             my $str = $self->bare;
169              
170             The trailing slash causes trouble when trying to address a symlink to a
171             directory via a dir object. Thus, C<-l $dir> doesn't work, but
172             C<$dir-El> does the same thing as C<-l $dir-Ebare>.
173              
174             =cut
175              
176             sub bare {
177 149     149 1 192 my $self = shift;
178 149         166 my @dirs = @{$self->{dirs}};
  149         411  
179 149 50       332 @dirs or return('/');
180             # TODO volume
181 149         2959 join('/', @dirs); # always a trailing slash
182             } # end subroutine bare definition
183             ########################################################################
184              
185             =head2 file
186              
187             Create a filename object with $dir as its parent.
188              
189             my $file = $dir->file($filename);
190              
191             my $file = $dir + $filename;
192              
193             =cut
194              
195             sub file {
196 196     196 1 2340 my $self = shift;
197 196         346 my ($name, $rev) = @_;
198 196 50       451 $rev and croak("bah");
199              
200             # filename might have dir parts
201 196 100       646 if($name =~ m#/#) {
202 1         9 my $bit = $self->file_class->new($name);
203 1         43 return $self->file_class->new_direct(
204             dir => $self->subdir($bit->dirname),
205             file => $bit->basename
206             );
207             }
208              
209 195         1470 return($self->file_class->new_direct(dir => $self, file => $name));
210             } # end subroutine file definition
211             ########################################################################
212              
213             =head2 append
214              
215             Append a string only to the last directory part.
216              
217             $dir->append('.tmp');
218              
219             $dir %= "something";
220              
221             =cut
222              
223             sub append {
224 2     2 1 3 my $self = shift;
225 2         4 my ($bit, $rev) = @_;
226              
227 2 50       7 $rev and return($bit . "$self"); # stringify is out-of-order
228             #carp("appending $bit");
229             #$self = $self->clone;
230 2         6 $self->{dirs}[-1] .= $bit;
231 2         6 return($self);
232             } # end subroutine append definition
233             ########################################################################
234              
235             =head2 subdir
236              
237             $newdir = $dir->subdir('foo');
238              
239             $newdir = $dir / 'foo';
240              
241             =cut
242              
243             sub subdir {
244 145     145 1 2120 my $self = shift;
245 145         243 my ($name, $rev) = @_;
246 145 50       304 $rev and croak("bah");
247              
248             # appending to cwd means starting over
249 145 100       337 return($self->new($name)) if($self->is_cwd);
250              
251 141         359 my %newbits = $self->_init($name);
252 141         517 $self = $self->clone;
253 141         183 push(@{$self->{dirs}}, @{$newbits{dirs}});
  141         279  
  141         345  
254 141         477 $self;
255             } # end subroutine subdir definition
256             ########################################################################
257              
258             =head2 part
259              
260             Returns the $i'th part of the directory list.
261              
262             my $part = $dir->part($i);
263              
264             $dir->part(-1) is like $dir->basename, but not an object and not quite
265             like File::Basename::basename() when it comes to the / directory.
266              
267             =cut
268              
269             sub part {
270 7     7 1 14 my $self = shift;
271 7         9 my ($i) = @_;
272 7         37 return($self->{dirs}[$i]);
273             } # end subroutine part definition
274             ########################################################################
275              
276             =head2 end
277              
278             Shorthand for part(-1);
279              
280             =cut
281              
282 0     0 1 0 sub end {shift->part(-1)};
283              
284             =head2 parts
285              
286             Retrieve the inner list of the directory's parts.
287              
288             my @parts = $dir->parts;
289              
290             my @parts = $dir->parts(0..2);
291              
292             The returned parts will be contiguous, but the request can be a
293             two-element list (and can also start or end at negative indices.)
294              
295             my @parts = $dir->parts(3, 7);
296              
297             my @parts = $dir->parts(3, -1);
298              
299             my @parts = $dir->parts(-5, -1);
300              
301             =cut
302              
303             sub parts {
304 5     5 1 9 my $self = shift;
305 5         10 my @want = @_;
306 5 50       12 @want or return(@{$self->{dirs}});
  0         0  
307 5 50       17 if(@want == 2) {
308 5         9 foreach my $end (@want) {
309 10 100       30 $end = $#{$self->{dirs}} + 1 + $end if($end < 0);
  5         16  
310             }
311 5 50       15 if($want[0] > $want[1]) {
312 0         0 croak("first endpoint '$want[0]' is after last '$want[1]'");
313             }
314 5         16 @want = $want[0]..$want[1];
315             }
316             # TODO else check contiguity?
317 5         8 return(@{$self->{dirs}}[@want]);
  5         22  
318             } # end subroutine parts definition
319             ########################################################################
320              
321             =head2 slice
322              
323             Returns a new dir object as the return of parts().
324              
325             my $slice = $dir->slice(0);
326              
327             my $slice = $dir->slice(0,3);
328              
329             =cut
330              
331             sub slice {
332 5     5 1 15 my $self = shift;
333 5         27 $self = $self->clone;
334 5         17 @{$self->{dirs}} = $self->parts(@_);
  5         20  
335 5         27 return($self);
336             } # end subroutine slice definition
337             ########################################################################
338              
339             =head2 map
340              
341             Execute a callback on each part of $dir. The sub should modify $_ (yes,
342             this is slightly unlike the map() builtin.)
343              
344             If $parts is defined as an integer or array reference of integers, it
345             will be treated as a slice on the directory parts to which the map
346             should be applied.
347              
348             $dir->map(sub {...}, [@parts]);
349              
350             $dir &= sub {s/foo$/bar/};
351              
352             So, to modify only the first directory part:
353              
354             $dir->map(sub {s/foo$/bar/}, 0);
355              
356             =cut
357              
358             sub map :method {
359 0     0 1 0 my $self = shift;
360 0         0 my ($sub, $parts) = @_;
361 0         0 my @parts = defined($parts) ? (ref($parts) ? @$parts : $parts) :
362 0 0       0 0..($#{$self->{dirs}});
    0          
363             # TODO actually use the parts() code for this
364             # warn "@parts";
365 0         0 foreach my $dir (@{$self->{dirs}}[@parts]) {
  0         0  
366 0         0 local $_ = $dir;
367 0         0 $sub->();
368 0         0 $dir = $_;
369             }
370 0         0 $self;
371             } # end subroutine map definition
372             ########################################################################
373              
374             =head1 Properties
375              
376             =head2 is_cwd
377              
378             True if the $dir represents a relative (e.g. '.') directory.
379              
380             my $bool = $dir->is_cwd;
381              
382             =cut
383              
384             sub is_cwd {
385 661     661 1 1105 my $self = shift;
386              
387 661         757 my @dirs = @{$self->{dirs}};
  661         4295  
388 661   100     5315 return(@dirs == 1 and $dirs[0] eq '.');
389             } # end subroutine is_cwd definition
390             ########################################################################
391              
392             =for note
393             dirname('.') and basename('.') are both '.' -- also true for '/'
394              
395             =head2 basename
396              
397             Returns the last part of the path as a Dir object.
398              
399             my $bit = $dir->basename;
400              
401             =cut
402              
403             sub basename {
404 12     12 1 1940 my $self = shift;
405 12         57 return($self->new($self->{dirs}[-1]));
406             } # end subroutine basename definition
407             ########################################################################
408              
409             =head2 dirname
410              
411             Returns the parent parts of the path as a Dir object.
412              
413             my $parent = $dir->dirname;
414              
415             =cut
416              
417             sub dirname {
418 13     13 1 3890 my $self = shift;
419 13         61 $self = $self->clone;
420 13         39 my $dirs = $self->{dirs};
421 13 100 100     86 if(@$dirs == 1 and $dirs->[0] eq '') {
422 1         4 return($self->new('/'));
423             }
424 12         20 pop(@$dirs);
425 12 100       43 @$dirs or return($self->new);
426 8         40 return($self);
427             } # end subroutine dirname definition
428             ########################################################################
429              
430             =head2 absolute
431              
432             Get an absolute name (without checking the filesystem.)
433              
434             my $abs = $dir->absolute;
435              
436             =cut
437              
438             sub absolute {
439 2     2 1 420 my $self = shift;
440 2 50       6 return $self if $self->is_absolute;
441 2         6 return $self->new(File::Spec->rel2abs($self->stringify));
442             } # end subroutine absolute definition
443             ########################################################################
444              
445             =head2 absolutely
446              
447             Get an absolute path (resolved on filesystem, so it must exist.)
448              
449             my $abs = $dir->absolutely;
450              
451             =cut
452              
453             sub absolutely {
454 13     13 1 1849 my $self = shift;
455 13         59 my $res = Cwd::abs_path($self->stringify);
456 13 50       73 defined($res) or croak("$self absolutely() not found");
457 13         52 return $self->new($res);
458             } # end subroutine absolutely definition
459             ########################################################################
460              
461             =head1 Doing stuff
462              
463             =head2 open
464              
465             Calls opendir(), but throws an error if it fails.
466              
467             my $dh = $dir->open;
468              
469             Returns a directory handle, for e.g. readdir().
470              
471             my @files = map({$dir + $_} grep({$_ !~ m/^\./} readdir($dh)));
472              
473             =cut
474              
475             sub open :method {
476 15     15 1 23 my $self = shift;
477              
478 15 50       135 opendir(my $dh, "$self") or die "cannot opendir '$self' $!";
479 15         38 return($dh);
480             } # end subroutine open definition
481             ########################################################################
482              
483             =head2 touch
484              
485             Update the timestamp of a directory (croak if it doesn't exist.)
486              
487             $dir->touch;
488              
489             =cut
490              
491             sub touch {
492 1     1 1 2 my $self = shift;
493 1         14 $self->utime(time);
494             } # end subroutine touch definition
495             ########################################################################
496              
497             =head2 list
498              
499             my @paths = $dir->list(all => 1);
500              
501             =cut
502              
503             sub list {
504 3     3 1 1038 my $self = shift;
505              
506 3 100       21 map({my $d = $self/$_; -d $d ? $d : $self+$_} $self->contents(@_));
  9         129  
  9         28  
507             } # end subroutine list definition
508             ########################################################################
509              
510             =head2 lister
511              
512             my $subref = $dir->lister(all => 1);
513              
514             =cut
515              
516             sub lister {
517 12     12 1 21 my $self = shift;
518 12         38 my $csub = $self->iterate_contents(@_);
519             my $sub = sub {
520 116 50   116   309 $csub or return();
521 116         335 while(defined(my $n = $csub->())) {
522 104         211 my $d = $self/$n;
523 104 100       231 return(-d $d->bare ? $d : $self+$n)
524             }
525 12         19 $csub = undef;
526 12         99 return();
527 12         50 };
528 12         38 return($sub);
529             } # end subroutine lister definition
530             ########################################################################
531              
532             =head2 contents
533              
534             Equivelant to readdir. With the 'all' option true, returns hidden names
535             too (but not the '.' and '..' entries.)
536              
537             The return values are strings, not File::Fu objects.
538              
539             my @names = $dir->contents(all => 1);
540              
541             =cut
542              
543             sub contents {
544 3     3 1 9 my $self = shift;
545 3 50       28 (@_ % 2) and croak('odd number of items in options hash');
546 3         9 my %opts = @_;
547 3         61 my $dh = $self->open;
548             # XXX needs more cross-platformness
549 3 50       10 $opts{all} and return(grep({$_ !~ m/^\.{1,2}$/} readdir($dh)));
  0         0  
550 3         92 return(grep({$_ !~ m/^\./} readdir($dh)));
  15         107  
551             } # end subroutine contents definition
552             ########################################################################
553              
554             =head2 iterate_contents
555              
556             Returns a subref which will iterate over the directory's contents.
557              
558             my $subref = $dir->iterate_contents(all => 1);
559              
560             =cut
561              
562             sub iterate_contents {
563 12     12 1 16 my $self = shift;
564 12 50       39 (@_ % 2) and croak('odd number of items in options hash');
565 12         24 my %opts = @_;
566 12         20 my $all = $opts{all};
567 12         30 my $dh = $self->open;
568             # XXX needs more cross-platformness
569             return sub {
570 116 50   116   213 $dh or return();
571 116         866 while(defined(my $n = readdir($dh))) {
572 128 100       305 if($all) {
573 122 100       547 return($n) unless($n =~ m/^\.{1,2}$/);
574             }
575             else {
576 6 100       59 return($n) unless($n =~ m/^\./);
577             }
578             }
579 12         23 $dh = undef;
580 12         195 return();
581 12         61 };
582             } # end subroutine iterate_contents definition
583             ########################################################################
584              
585             =head2 find
586              
587             Recursively search a directory's contents for items where the supplied
588             coderef (matcher) returns true. The matcher will be invoked with the
589             topic (C<$_>) set to the current path (which is either a Dir or File
590             object.) The return values will be File::Fu::File or File::Fu::Dir
591             objects.
592              
593             If your matcher returns true, the topic will be added to the return
594             values.
595              
596             my @paths = $dir->find(sub {m/foo/});
597              
598             There is a knob for controlling recursion, which is the first argument
599             to your matcher.
600              
601             my @pm_files = $dir->find(sub {
602             return shift->prune
603             if($_->is_dir and $_->part(-1) =~ m/^\.svn$/);
604             $_->is_file and m/\.pm$/;
605             });
606              
607             =over
608              
609             =item Differences from File::Find::find()
610              
611             The invocant (C<$dir> aka '.') is not examined (because this is an
612             object method, there is always only one starting path.)
613              
614             The topic is always absolute in the same sense as the invocant. That
615             is, if C<$dir> is relative to your current directory, then so are the
616             topics and return values. If C<$dir> is absolute, so are the topics and
617             return values.
618              
619             =back
620              
621             =cut
622              
623             sub find {
624 3     3 1 1136 my $self = shift;
625              
626 3         6 my @return;
627 3         14 my $finder = $self->finder(@_);
628 3         43 while(defined(my $ans = $finder->())) {
629 12 50       32 $ans or next;
630 12         71 push(@return, $ans);
631             }
632 3         45 return(@return);
633             } # end subroutine find definition
634             ########################################################################
635              
636             =head2 finder
637              
638             Returns an iterator for finding files. This iterator does everything
639             that find() does, but returns one path at a time. Returns undef when
640             exhausted and zero when it is just taking a break.
641              
642             my $subref = $dir->finder(sub {$_->is_file and $_->file =~ m/foo/});
643              
644             This allows a non-blocking find.
645              
646             while(defined(my $path = $subref->())) {
647             $path or next; # 0 means 'not done yet'
648             # do something with $path (a file or dir object)
649             }
650              
651             The find() method is implemented in terms of finder() by simply using a
652             while() loop and accumulating the return values.
653              
654             =cut
655              
656             sub finder {
657 4     4 1 1015 my $self = shift;
658 4         10 my ($matcher, @opt) = @_; # TODO support options e.g. loops
659              
660 4         14 my %opt = (all => 1);
661              
662 4         7 my $reader;
663             my @stack;
664             my $it = sub {
665 25     25   73 my $loops = 0;
666 111   66     271 FIND: {
667 25         26 $reader ||= $self->lister(all => $opt{all});
668 111         106 $loops++;
669 111 100       178 if(defined(my $path = $reader->())) {
670 100 100 100     363 if($path->is_dir and not $path->l) {
671 8         28 push(@stack, [$self, $reader]);
672 8         15 ($self, $reader) = ($path, undef);
673             }
674 100         127 local $_ = $path;
675 100         411 my $ok = $matcher->(my $knob = File::Fu::Dir::FindKnob->new);
676 100 100 100     3174 if($knob->pruned and not $path->l) { # XXX nofollow assumption
677 1         4 ($self, $reader) = @{pop(@stack)};
  1         2  
678             }
679 100 100       567 if($ok) {
680 21         87 return($path);
681             }
682 79 50       356 redo FIND if($loops < 50);
683 0         0 return(0); # no match, but continue
684             }
685             else {
686 11 100       32 @stack or return();
687 7         8 ($self, $reader) = @{pop(@stack)};
  7         17  
688 7         28 redo FIND;
689             }
690             }
691 4         43 };
692 4         13 return($it);
693             } # end subroutine finder definition
694             ########################################################################
695              
696             =head2 The FindKnob object
697              
698             The FindKnob object allows you to control the next steps of find().
699             Methods called on it will typically return a value which also makes
700             sense as a return value of your matcher sub. Thus the idiom:
701              
702             $dir->find(sub {return shift->prune if(condition); ...})
703              
704             =over
705              
706             =item prune
707              
708             Do not recurse into the topic directory. Returns false.
709              
710             =back
711              
712             =cut
713              
714             BEGIN {
715             package File::Fu::Dir::FindKnob;
716 13     13   177 use Class::Accessor::Classy;
  13         25  
  13         99  
717 13     13   4462 with 'new';
718 13         1038 ri 'pruned';
719 13     13   3142 no Class::Accessor::Classy;
  13         39  
  13         74  
720 2     2   77 sub prune {shift->set_pruned(1); 0}
  2         47  
721             } # File::Fu::Dir::FindKnob
722             ########################################################################
723              
724             =head2 mkdir
725              
726             Create the directory or croak with an error.
727              
728             $dir->mkdir;
729              
730             $dir->mkdir(0700);
731              
732             =cut
733              
734             sub mkdir :method {
735 15     15 1 1671 my $self = shift;
736 15 100       59 if(@_) {
737 1         3 my $mode = shift(@_);
738 1 50       3 mkdir($self, $mode) or croak("cannot mkdir('$self', $mode) $!");
739             }
740             else {
741 14 100       157 mkdir($self) or croak("cannot mkdir('$self') $!");
742             }
743 14         57 return($self);
744             } # end subroutine mkdir definition
745             ########################################################################
746              
747             =head2 create
748              
749             Create the directory, with parents if needed.
750              
751             $dir->create;
752              
753             =cut
754              
755             sub create {
756 1     1 1 2 my $self = shift;
757             # TODO pass mode, but the verbose parameter is silly (should have been
758             # a callback or something -- so we'll end up reimplementing mkpath?)
759 1         5 File::Path::mkpath("$self");
760 1         2 return($self);
761             } # end subroutine create definition
762             ########################################################################
763              
764             =head2 rmdir
765              
766             Remove the directory or croak with an error.
767              
768             $dir->rmdir;
769              
770             =cut
771              
772             sub rmdir :method {
773 9     9 1 194 my $self = shift;
774 9 100       25 rmdir($self) or croak("cannot rmdir('$self') $!");
775             } # end subroutine rmdir definition
776             ########################################################################
777              
778             =head2 remove
779              
780             Remove the directory and all of its children.
781              
782             $dir->remove;
783              
784             =cut
785              
786             sub remove {
787 8     8 1 2108 my $self = shift;
788 8         103 my $dir = $self->stringify;
789 8         9936 File::Path::rmtree($dir);
790 8 50       377 -e $dir and croak("rmtree failed"); # XXX rmtree is buggy
791             } # end subroutine remove definition
792             ########################################################################
793              
794             =head2 unlink
795              
796             $link->unlink;
797              
798             =cut
799              
800             sub unlink :method {
801 8     8 1 1921 my $self = shift;
802 8 50       32 $self->l or croak("not a link");
803 8 50       23 unlink($self->bare) or croak("unlink '$self' failed $!");
804             } # end subroutine unlink definition
805             ########################################################################
806              
807             =head2 symlink
808              
809             Create a symlink which points to $dir.
810              
811             my $link = $dir->symlink($linkname);
812              
813             Note that symlinks are relative to where they live, so if $dir is a
814             relative path, it must be relative to $linkname.
815              
816             =cut
817              
818             sub symlink :method {
819 9     9 1 39 my $self = shift;
820 9         18 my ($name) = @_;
821              
822 9         26 $name =~ s#/$##; # stringify and strip
823 9 50       23 symlink($self, $name) or
824             croak("symlink '$self' to '$name' failed $!");
825 9         35 return($self->new($name));
826             } # end subroutine symlink definition
827             ########################################################################
828              
829             =head2 readlink
830              
831             my $to = $file->readlink;
832              
833             =cut
834              
835             sub readlink :method {
836 1     1 1 7 my $self = shift;
837 1         6 my $name = readlink($self->bare);
838 1 50       8 defined($name) or croak("cannot readlink '$self' $!");
839 1         11 return($self->new($name));
840             } # end subroutine readlink definition
841             ########################################################################
842              
843             =head1 Changing Directories
844              
845              
846             =head2 chdir
847              
848             Change to the directory in self, returning a new '.' directory object.
849              
850             $dir = $dir->chdir;
851              
852             =cut
853              
854             sub chdir :method {
855 4     4 1 19 my $self = shift;
856 4 50       30 chdir($self) or croak("cannot chdir '$self' $!");
857             # should return a new '.' object ?
858 4         58 return($self->new('.'));
859             } # end subroutine chdir definition
860             ########################################################################
861              
862             =head2 chdir_for
863              
864             Change to $dir and run the given subroutine. The sub will be passed a
865             './' directory object.
866              
867             $dir->chdir_for(sub {...});
868              
869             =cut
870              
871             sub chdir_for {
872 1     1 1 26 my $self = shift;
873 1         5 my ($sub) = @_;
874             # we need to guarantee that we return, so we must implement the scoped
875             # version in order to implement the wrapper.
876 1         7 my $dot = $self->chdir_local;
877             # XXX bah. the $token binds weirdly in 5.6.2
878 1         6 return $sub->($self->new('.'));
879             } # end subroutine chdir_for definition
880             ########################################################################
881              
882             =head2 chdir_local
883              
884             Change to $dir, but return to the current cwd when $token goes out of
885             scope.
886              
887             my $token = $self->chdir_local;
888              
889             =cut
890              
891             sub chdir_local {
892 1     1 1 6 my $self = shift;
893 1         17 my $now = $self->top_class->cwd;
894 1         22 $self->chdir;
895 1         30 return $self->token_class->new->return_to($now);
896             } # end subroutine chdir_local definition
897             ########################################################################
898             BEGIN {
899             package File::Fu::Dir::Token;
900 13     13   18883 our @ISA = qw('File::Fu::Dir);
901             sub return_to {
902 1     1   3 my $self = shift(@_);
903 1 50       152 $self->{return_to} = shift(@_) or croak("invalid usage");
904 1         6 return($self);
905             }
906 1 50   1   13 sub DESTROY { my $ret = shift->{return_to} or return; $ret->chdir; }
  1         4  
907             }
908             ########################################################################
909              
910             =head1 Temporary Directories and Files
911              
912             These methods use the $dir object as a parent location for the temp
913             path. To use your system's global temp space (e.g. '/tmp/'), just
914             replace $dir with 'File::Fu'.
915              
916             File::Fu->temp_dir; # '/tmp/'
917             File::Fu->dir->temp_dir; # './'
918             File::Fu->dir("foo")->temp_dir; # 'foo/'
919              
920             File::Fu->temp_file; # '/tmp/'
921             File::Fu->dir->temp_file; # './'
922             File::Fu->dir("foo")->temp_file; # 'foo/'
923              
924             =head2 temp_dir
925              
926             Return a temporary directory in $dir.
927              
928             my $dir = $dir->temp_dir;
929              
930             =cut
931              
932             sub temp_dir {
933 3     3 1 6 my $self = shift;
934 3         18 $self->temp_dir_class->new($self, @_);
935             } # end subroutine temp_dir definition
936             ########################################################################
937              
938             =head2 temp_file
939              
940             Return a filehandle to a temporary file in $dir.
941              
942             my $handle = $dir->temp_file;
943              
944             =cut
945              
946             sub temp_file {
947 4     4 1 7 my $self = shift;
948 4         14 $self->temp_file_class->new($self, @_);
949             } # end subroutine temp_file definition
950             ########################################################################
951              
952             =head1 AUTHOR
953              
954             Eric Wilhelm @
955              
956             http://scratchcomputing.com/
957              
958             =head1 BUGS
959              
960             If you found this module on CPAN, please report any bugs or feature
961             requests through the web interface at L. I will be
962             notified, and then you'll automatically be notified of progress on your
963             bug as I make changes.
964              
965             If you pulled this development version from my /svn/, please contact me
966             directly.
967              
968             =head1 COPYRIGHT
969              
970             Copyright (C) 2008 Eric L. Wilhelm, All Rights Reserved.
971              
972             =head1 NO WARRANTY
973              
974             Absolutely, positively NO WARRANTY, neither express or implied, is
975             offered with this software. You use this software at your own risk. In
976             case of loss, no person or entity owes you anything whatsoever. You
977             have been warned.
978              
979             =head1 LICENSE
980              
981             This program is free software; you can redistribute it and/or modify it
982             under the same terms as Perl itself.
983              
984             =cut
985              
986             require File::Fu;
987             # vi:ts=2:sw=2:et:sta
988             1;