File Coverage

blib/lib/File/Fu.pm
Criterion Covered Total %
statement 49 65 75.3
branch 6 18 33.3
condition 1 3 33.3
subroutine 18 20 90.0
pod 9 9 100.0
total 83 115 72.1


line stmt bran cond sub pod time code
1             package File::Fu;
2             $VERSION = v0.0.8;
3              
4 13     13   357981 use warnings;
  13         34  
  13         431  
5 13     13   79 use strict;
  13         25  
  13         441  
6 13     13   80 use Carp;
  13         24  
  13         1303  
7              
8             =head1 NAME
9              
10             File::Fu - file and directory objects
11              
12             =head1 SYNOPSIS
13              
14             The directory constructor:
15              
16             use File::Fu;
17              
18             my $dir = File::Fu->dir("bar");
19             print "$dir\n"; # 'bar/'
20              
21             my $file = $dir + 'bar.txt';
22             print "$file\n"; # 'bar/bar.txt'
23              
24             my $d2 = $dir % 'baz'; # 'barbaz/'
25             my $d3 = $dir / 'bat'; # 'bar/bat/'
26              
27             my $file2 = $dir / 'bat' + 'foo.txt'; # 'bar/bat/foo.txt'
28              
29             The file constructor:
30              
31             my $file = File::Fu->file("foo");
32             $file->e and warn "$file exists";
33             $file->l and warn "$file is a link";
34             warn "file is in ", $file->dir;
35              
36             =head1 ABOUT
37              
38             This class provides the toplevel interface to File::Fu directory and
39             file objects, with operator overloading which allows precise path
40             composition and support for most builtin methods, as well as creation of
41             temporary files/directories, finding files, and more.
42              
43             The interface and style are quite different than the perl builtins or
44             File::Spec. The syntax is concise. Errors are thrown with croak(), so
45             you never need to check a return code.
46              
47             =cut
48              
49 13     13   67 use Cwd ();
  13         23  
  13         347  
50              
51 13     13   11087 use File::Fu::File;
  13         41  
  13         594  
52 13     13   9706 use File::Fu::Dir;
  13         49  
  13         403  
53 13     13   77 use File::Spec ();
  13         23  
  13         274  
54              
55 13     13   71 use constant dir_class => 'File::Fu::Dir';
  13         75  
  13         817  
56 13     13   516 use constant file_class => 'File::Fu::File';
  13         31  
  13         12471  
57              
58             =head1 Constructors
59              
60             The actual objects are in the 'Dir' and 'File' sub-namespaces.
61              
62             =head2 dir
63              
64             my $dir = File::Fu->dir($path);
65              
66             See L
67              
68             =cut
69              
70             sub dir {
71 33     33 1 4189 my $package = shift;
72              
73 33 50       136 $package or croak("huh?");
74             # also as a function call
75 33 50 33     448 unless($package and $package->isa(__PACKAGE__)) {
76 0         0 unshift(@_, $package);
77 0         0 $package = __PACKAGE__;
78             }
79              
80 33         496 $package->dir_class->new(@_);
81             } # end subroutine dir definition
82             ########################################################################
83              
84             =head2 file
85              
86             my $file = File::Fu->file($path);
87              
88             See L
89              
90             =cut
91              
92             sub file {
93 20     20 1 2799 my $package = shift;
94              
95             # also as a function call
96 20 50       246 unless($package->isa(__PACKAGE__)) {
97 0         0 unshift(@_, $package);
98 0         0 $package = __PACKAGE__;
99             }
100              
101 20         320 $package->file_class->new(@_);
102             } # end subroutine file definition
103             ########################################################################
104              
105             =head1 Class Constants
106              
107             =head2 tmp
108              
109             Your system's '/tmp/' directory (or equivalent of that.)
110              
111             my $dir = File::Fu->tmp;
112              
113             =cut
114              
115             {
116             my $tmp; # XXX needs locking?
117             sub tmp {
118 5     5 1 32 my $package = shift;
119 5 100       20 $tmp and return($tmp);
120 2         223 return($tmp = $package->dir(File::Spec->tmpdir));
121             }}
122             ########################################################################
123              
124             =head2 home
125              
126             User's $HOME directory.
127              
128             my $dir = File::Fu->home;
129              
130             =cut
131              
132             {
133             my $home; # XXX needs locking!
134             sub home {
135 0     0 1 0 my $package = shift;
136 0 0       0 $home and return($home);
137 0         0 return($home = $package->dir($ENV{HOME}));
138             }} # end subroutine home definition
139             ########################################################################
140              
141             =head2 program_name
142              
143             The absolute name of your program. This will be relative from the time
144             File::Fu was loaded. It dies if the name is '-e'.
145              
146             my $prog = File::Fu->program_name;
147              
148             If File::Fu was loaded after a chdir and the $0 was relative, calling
149             program_name() throws an error. (Unless you set $0 correctly before
150             requiring File::Fu.)
151              
152             =head2 program_dir
153              
154             Returns what typically corresponds to program_name()->dirname, but
155             just the compile-time cwd() when $0 is -e/-E.
156              
157             my $dir = File::Fu->program_dir;
158              
159             =cut
160              
161             {
162             # fun startup stuff and various logic:
163             my $prog = $0;
164             my $name_sub;
165             my $dir_sub;
166             if(lc($prog) eq '-e') {
167             my $prog_dir = Cwd::cwd();
168             $dir_sub = eval(qq(sub {shift->dir("$prog_dir")}));
169             $name_sub = eval(qq(sub {croak("program_name => '$prog'")}));
170             }
171             else {
172             if(-e $prog) {
173             my $prog_name = __PACKAGE__->file($prog)->absolutely;
174             my $prog_dir = $prog_name->dirname;
175 1     1   54 $name_sub = eval(qq(sub {shift->file('$prog_name')}));
176 1     1   7 $dir_sub = eval(qq(sub {shift->dir('$prog_dir')}));
177             }
178             else {
179             # runtime error
180             $dir_sub = sub {croak("$prog not found => no program_dir known")};
181             $name_sub = sub {croak("$prog not found => no program_name known")};
182             }
183             }
184             *program_name = $name_sub;
185             *program_dir = $dir_sub;
186             } # program_name/program_dir
187             ########################################################################
188              
189             =head1 Class Methods
190              
191             =head2 THIS_FILE
192              
193             A nicer way to say __FILE__.
194              
195             my $file = File::Fu->THIS_FILE;
196              
197             =cut
198              
199             sub THIS_FILE {
200 1     1 1 3 my $package = shift;
201 1         4 my $name = (caller)[1];
202 1         4 return $package->file($name);
203             } # end subroutine THIS_FILE definition
204             ########################################################################
205              
206             =head2 cwd
207              
208             The current working directory.
209              
210             my $dir = File::Fu->cwd;
211              
212             =cut
213              
214             sub cwd {
215 3     3 1 643 my $package = shift;
216              
217 3 50       524144 defined(my $ans = Cwd::cwd()) or croak("cwd() failed");
218 3         102 return $package->dir($ans);
219             } # end subroutine cwd definition
220             ########################################################################
221              
222             =head2 which
223              
224             Returns File::Fu::File objects of ordered candidates for $name found in
225             the path.
226              
227             my @prog = File::Fu->which($name) or die "cannot find $name";
228              
229             If called in scalar context, returns a single File::Fu::File object or throws an error if no candidates were found.
230              
231             my $prog = File::Fu->which($name);
232              
233             =cut
234              
235             sub which {
236 0     0 1 0 my $package = shift;
237 0 0       0 croak("must have an argument") unless(@_);
238 0         0 my ($what) = @_;
239              
240 0         0 require File::Which;
241 0 0       0 if(wantarray) {
242 0         0 return map({$package->file($_)} File::Which::which($what));
  0         0  
243             }
244             else {
245 0 0       0 my $found = scalar(File::Which::which($what)) or
246             croak("cannot locate '$what' in PATH");
247 0         0 return $package->file($found);
248             }
249             } # which ##############################################################
250              
251             =head1 Temporary Directories and Files
252              
253             These class methods call the corresponding File::Fu::Dir methods on the
254             value of tmp(). That is, you get a temporary file/dir in the '/tmp/'
255             directory.
256              
257             =head2 temp_dir
258              
259             my $dir = File::Fu->temp_dir;
260              
261             =cut
262              
263             sub temp_dir {
264 1     1 1 12 my $package = shift;
265 1         5 $package->tmp->temp_dir(@_);
266             } # end subroutine temp_dir definition
267             ########################################################################
268              
269             =head2 temp_file
270              
271             my $handle = File::Fu->temp_file;
272              
273             =cut
274              
275             sub temp_file {
276 3     3 1 1810 my $package = shift;
277 3         13 $package->tmp->temp_file(@_);
278             } # end subroutine temp_file definition
279             ########################################################################
280              
281             =head1 Operators
282              
283             If you choose not to use the overloaded operators, you can just say
284             C<$obj-Estringify()> or "$obj" whenever you want to drop the
285             object-y nature and treat the path as a string.
286              
287             The operators can be convenient for building-up path names, but you
288             probably don't want to think of them as "math on filenames", because
289             they are nothing like that.
290              
291             The '+' and '/' operators only apply to directory objects.
292              
293             op method mnemonic
294             -- ---------------- --------------------
295             + $d->file($b) ............. plus (not "add")
296             / $d->subdir($b) ........... slash (not "divide")
297              
298             The other operators apply to both files and directories.
299              
300             op method mnemonic
301             -- ---------------- --------------------
302             %= $p->append($b) ........... mod(ify)
303             % $p->clone->append($b)
304             &= $p->map(sub{...}) ........ invoke subref
305             & $p->clone->map(sub {...})
306              
307             Aside: It would be more natural to use C<.=> as append(), but the way
308             perl compiles C<"$obj foo"> into C<$obj . " foo"> makes it impossible to
309             do the right thing because the lines between object and string are too
310             ambiguous.
311              
312             =head1 Subclassing
313              
314             You may wish to subclass File:Fu and override the dir_class() and/or
315             file_class() class methods to point to your own Dir/File subclasses.
316              
317             my $class = 'My::FileFu';
318             my $dir = $class->dir("foo");
319              
320             See L and L for more info.
321              
322             =head2 dir_class
323              
324             File::Fu->dir_class # File::Fu::Dir
325              
326             =head2 file_class
327              
328             File::Fu->file_class # File::Fu::File
329              
330             =head1 See Also
331              
332             L if I need to explain my motivations.
333              
334             L, from which many an idea was taken.
335              
336             L, L, L, L, L,
337             L, L, L, L.
338              
339             =head1 AUTHOR
340              
341             Eric Wilhelm @
342              
343             http://scratchcomputing.com/
344              
345             =head1 BUGS
346              
347             If you found this module on CPAN, please report any bugs or feature
348             requests through the web interface at L. I will be
349             notified, and then you'll automatically be notified of progress on your
350             bug as I make changes.
351              
352             If you pulled this development version from my /svn/, please contact me
353             directly.
354              
355             =head1 COPYRIGHT
356              
357             Copyright (C) 2008 Eric L. Wilhelm, All Rights Reserved.
358              
359             =head1 NO WARRANTY
360              
361             Absolutely, positively NO WARRANTY, neither express or implied, is
362             offered with this software. You use this software at your own risk. In
363             case of loss, no person or entity owes you anything whatsoever. You
364             have been warned.
365              
366             =head1 LICENSE
367              
368             This program is free software; you can redistribute it and/or modify it
369             under the same terms as Perl itself.
370              
371             =cut
372              
373             # vi:ts=2:sw=2:et:sta
374             1;