File Coverage

lib/Badger/Filesystem/Directory.pm
Criterion Covered Total %
statement 29 43 67.4
branch 10 22 45.4
condition 8 12 66.6
subroutine 13 18 72.2
pod 17 17 100.0
total 77 112 68.7


line stmt bran cond sub pod time code
1             #========================================================================
2             #
3             # Badger::Filesystem::Directory
4             #
5             # DESCRIPTION
6             # OO representation of a file in a filesystem.
7             #
8             # AUTHOR
9             # Andy Wardley
10             #
11             #========================================================================
12              
13             package Badger::Filesystem::Directory;
14              
15             use Badger::Class
16 70         568 version => 0.01,
17             debug => 0,
18             base => 'Badger::Filesystem::Path',
19             dumps => 'path volume directory name stats',
20             constants => 'ARRAY HASH',
21             constant => {
22             is_directory => 1,
23             type => 'Directory',
24 70     70   2911 };
  70         134  
25              
26             *dir = \&directory;
27             *dirs = \&directories;
28             *is_dir = \&is_directory;
29              
30              
31             sub init {
32 243     243 1 444 my ($self, $config) = @_;
33 243         692 $self->init_path($config);
34 243         646 $self->init_options($config);
35 243         1124 return $self;
36             }
37              
38             sub base {
39 77     77 1 214 $_[0];
40             }
41              
42             sub directory {
43 53     53 1 229 my $self = shift;
44 53 100 100     192 my $opts = (@_ > 1 && ref $_[-1] eq HASH) ? pop(@_) : $self->{ options }; # needs work
45             return (@_ || %$opts)
46             ? $self->filesystem->directory( @_ ? $self->relative(@_) : (), $opts )
47 53 50 66     237 : $self->{ directory };
    100          
48             }
49              
50             sub file {
51 28     28 1 161 my $self = shift;
52 28 100 66     164 my $opts = @_ && ref $_[-1] eq HASH ? pop(@_) : $self->{ options };
53 28 50 33     152 return (@_ || %$opts)
    50          
54             ? $self->filesystem->file( @_ ? $self->relative(@_) : (), $opts )
55             : $self->error( missing => 'file name' );
56             }
57              
58             sub canonical {
59 4     4 1 9 my $self = shift;
60 4         8 $self->filesystem->slash_directory( $self->{ path } );
61             }
62            
63             sub exists {
64 38     38 1 93 my $self = shift;
65 38         110 $self->filesystem->directory_exists($self->{ path });
66             }
67              
68             sub create {
69 5     5 1 13 my $self = shift;
70 5         17 $self->filesystem->create_directory($self->{ path }, @_);
71             }
72              
73             sub delete {
74 3     3 1 13 my $self = shift;
75 3         20 $self->filesystem->delete_directory($self->{ path }, @_);
76             }
77              
78             sub mkdir {
79 0     0 1 0 my $self = shift;
80             return @_
81 0 0       0 ? $self->directory(@_)->create
82             : $self->create;
83             }
84              
85             sub rmdir {
86 0     0 1 0 my $self = shift;
87             return @_
88 0 0       0 ? $self->directory(@_)->delete
89             : $self->delete;
90             }
91              
92             sub open {
93 0     0 1 0 my $self = shift;
94 0         0 $self->filesystem->open_directory($self->{ path }, @_);
95             }
96              
97             sub read {
98 3     3 1 42 my $self = shift->must_exist;
99 3         11 $self->filesystem->read_directory($self->{ path }, @_);
100             }
101              
102             sub children {
103 68     68 1 100 my $self = shift;
104 68 50       146 $self->debug("asking for $self->{ path } children\n") if $DEBUG;
105 68         142 return $self->filesystem->directory_children($self->{ path }, @_);
106             }
107              
108             sub files {
109 0     0 1 0 my $self = shift;
110 0         0 my @files = grep { $_->is_file } $self->children;
  0         0  
111 0 0       0 return wantarray ? @files : \@files;
112             }
113              
114             sub directories {
115 0     0 1 0 my $self = shift;
116 0         0 my @dirs = grep { $_->is_dir } $self->children;
  0         0  
117 0 0       0 return wantarray ? @dirs : \@dirs;
118             }
119              
120             sub accept {
121 60     60 1 141 $_[1]->visit_directory($_[0]);
122             }
123              
124             # Custom entry handler for the special case when a visitor starts visiting
125             # at a directory - in this case we move straight onto visiting the children
126             # of the directory rather than making a callback for the root directory.
127              
128             sub enter {
129 14     14 1 37 $_[1]->enter_directory($_[0]);
130             }
131              
132              
133             1;
134              
135              
136             =head1 NAME
137              
138             Badger::Filesystem::Directory - directory object
139              
140             =head1 SYNOPSIS
141              
142             # using either of Badger::Filesytem constructor subroutines
143             use Badger::Filesystem 'Dir Directory';
144            
145             # use native OS-specific paths:
146             $dir = Dir('/path/to/dir');
147            
148             # or generic OS-independent paths
149             $dir = Dir('path', 'to', 'dir');
150              
151             # Dir is short for Directory if you prefer longness
152             $dir = Directory('/path/to/dir');
153             $dir = Directory('path', 'to', 'dir');
154              
155             # manual object construction
156             use Badger::Filesystem::Directory;
157            
158             # positional arguments
159             $dir = Badger::Filesystem::Directory->new('/path/to/file');
160             $dir = Badger::Filesystem::Directory->new(['path', 'to', 'file']);
161            
162             # named parameters
163             $dir = Badger::Filesystem::Directory->new(
164             path => '/path/to/dir' # native
165             );
166             $dir = Badger::Filesystem::Directory->new(
167             path => ['path', 'to', 'dir'] # portable
168             );
169            
170             # path inspection methods
171             $dir->path; # full path
172             $dir->directory; # same as path()
173             $dir->dir; # alias to directory()
174             $dir->base; # same as path()
175             $dir->volume; # path volume (e.g. C:)
176             $dir->is_absolute; # path is absolute
177             $dir->is_relative; # path is relative
178             $dir->exists; # returns true/false
179             $dir->must_exist; # throws error if not
180             @stats = $dir->stat; # returns list
181             $stats = $dir->stat; # returns list ref
182              
183             # path translation methods
184             $dir->relative; # relative to cwd
185             $dir->relative($base); # relative to $base
186             $dir->absolute; # relative to filesystem root
187             $dir->definitive; # physical file location
188             $dir->collapse; # resolve '.' and '..' in $file path
189            
190             # path comparison methods
191             $dir->above($another_path); # $dir is ancestor of $another_path
192             $dir->below($another_path); # $dir is descendant of $another_path
193            
194             # directory manipulation methods
195             $dir->create; # create directory
196             $dir->delete; # delete directory
197             $fh = $dir->open; # open directory to read
198            
199             # all-in-one read/write methods
200             @data = $dir->read; # return directory index
201             @kids = $dir->children; # objects for each file/subdir
202             @files = $dir->files; # objects for each file in dir
203             @dirs = $dir->dirs; # objects for each sub-dir in dir
204             @dirs = $dir->directories; # same as dirs()
205              
206             =head1 DESCRIPTION
207              
208             The C module is a subclass of
209             L for representing directories in a file system.
210              
211             You can create a file object using the C constructor function in
212             L. This is also available as C if you
213             prefer longer names.
214              
215             use Badger::Filesystem 'Dir';
216              
217             Directory paths can be specified as a single string using your native
218             filesystem format or as a list or reference to a list of items in the path for
219             platform-independent paths.
220              
221             my $dir = Dir('/path/to/dir');
222              
223             If you're concerned about portability to other operating systems and/or file
224             systems, then you can specify the directory path as a list or reference to a list
225             of component names.
226              
227             my $dir = Dir('path', 'to', 'dir');
228             my $dir = Dir(['path', 'to', 'dir']);
229              
230             =head1 METHODS
231              
232             In addition to the methods inherited from L, the
233             following methods are defined or re-defined.
234              
235             =head2 init(\%config)
236              
237             Customised initialisation method specific to directories.
238              
239             =head2 exists
240              
241             Returns true if the directory exists in the filesystem. Returns false if the
242             directory does not exists or if it is not a directory (e.g. a file).
243              
244             =head2 is_directory() / is_dir()
245              
246             This method returns true for all C instances.
247              
248             =head2 volume() / vol()
249              
250             Returns any volume defined as part of the path. This is most commonly used
251             on Win32 platforms to indicate drive letters, e.g. C.
252              
253             # on MS Windows
254             print Dir('C:\\foo\\bar')->volume; # C
255              
256             =head2 base()
257              
258             This always returns C<$self> for directories.
259              
260             =head2 canonical()
261              
262             This returns the canonoical representation of the directory path. This is
263             the absolute path with a trailing slash added (or whatever the relevant
264             directory separator is for your filesystem).
265              
266             print Dir('/foo/bar')->canonical; # /foo/bar/
267              
268             =head2 directory() / dir()
269              
270             Returns the complete directory path when called without arguments. This is
271             effectively the same thing as C or C returns, given that this
272             object I a directory.
273              
274             This can also be used with an argument to locate another directory relative
275             to this one.
276              
277             my $dir = Dir('/path/to/dir');
278             print $dir->dir; # /path/to/dir (auto-stringified)
279             print $dir->dir('subdir'); # /path/to/dir/subdir (ditto)
280              
281             Directories are returned as new C objects.
282             The above examples are relying on the auto-stringification to display
283             the path when printed.
284              
285             =head2 file($name)
286              
287             This method can be used to locate a file relative to the directory. The
288             file is returned as a L object.
289              
290             my $dir = Dir('/path/to/dir');
291             my $file = $dir->file('example.txt');
292             print $file->path; # /path/to/dir/example.txt
293             print $file; # same (auto-stringified)
294              
295             =head2 create()
296              
297             This method can be used to create the directory if it doesn't already exist.
298              
299             Dir('/path/to/dir')->create;
300              
301             =head2 delete()
302              
303             This method deletes the directory permanently. Use it wisely.
304              
305             Dir('/tmp/junk')->delete;
306              
307             =head2 mkdir($subdir)
308              
309             This method can be used to create a sub-directory.
310              
311             my $dir = Dir('/tmp');
312             $dir->mkdir('junk'); # /tmp/junk
313              
314             When called without an argument it has the same effect as L in
315             creating itself.
316              
317             my $dir = Dir('/tmp/junk');
318             $dir->mkdir; # same as $dir->create
319              
320             =head2 rmdir($subdir);
321              
322             This does the opposite of L but works in the same way. It can be
323             used to delete a sub-directory:
324              
325             my $dir = Dir('/tmp');
326             $dir->rmdir('junk'); # /tmp/junk
327              
328             Or the directory itself when called without an argument:
329              
330             my $dir = Dir('/tmp/junk');
331             $dir->rmdir; # same as $dir->delete
332              
333             =head2 open()
334              
335             This method opens the directory and returns an L handle to it.
336              
337             $fh = $dir->open;
338             while (defined($item = $fh->read)) {
339             print $item, "\n";
340             }
341              
342             =head2 read($all)
343              
344             This method read the contents of the directory. It returns a list (in list
345             context) or a reference to a list (in scalar context) containing the names
346             of the entries in the directory.
347              
348             my @entries = $dir->read; # list in list context
349             my $entries = $dir->read; # list ref in scalar context
350              
351             By default, the C<.> and C<..> directories (or the equivalents for your file
352             system) are ignored. Pass a true value for the C<$all> flag if you want
353             them included.
354              
355             =head2 children($all)
356              
357             Returns the entries of a directory as L or
358             L objects. Returns a list (in list context)
359             or a reference to a list (in scalar context).
360              
361             my @kids = $dir->children; # list in list context
362             my $kids = $dir->children; # list ref in scalar context
363              
364             =head2 files()
365              
366             Returns a list (in list context) or a reference to a list (in scalar context)
367             of all the files in a directory as L objects.
368              
369             my @files = $dir->files; # list in list context
370             my $files = $dir->files; # list ref in scalar context
371              
372             =head2 directories() / dirs()
373              
374             Returns a list (in list context) or a reference to a list (in scalar context)
375             of all the sub-directories in a directory as L
376             objects.
377              
378             my @dirs = $dir->dirs; # list in list context
379             my $dirs = $dir->dirs; # list ref in scalar context
380              
381             =head2 visit($visitor)
382              
383             Entry point for a filesystem visitor for visit a directory. A reference to a
384             L object (or subclass) should be passed as the
385             first argument.
386              
387             use Badger::Filesystem::Visitor;
388            
389             my $visitor = Badger::Filesystem::Visitor->new( in_dirs => 1 );
390             $dir->visit($visitor);
391              
392             Alternately, a list or reference to a hash array of named parameters may be
393             provided. These will be used to instantiate a new
394             L object (via the L
395             L method) which will then be applied
396             to the directory. If no arguments are passed then a visitor is created with a
397             default configuration.
398              
399             # either list of named params
400             $dir->visit( in_dirs => 1 );
401            
402             # or reference to hash array
403             $dir->visit({ in_dirs => 1});
404              
405             The method then calls the visitor
406             L
407             passing C<$self> as an argument to begin visiting the directory.
408              
409             =head2 accept($visitor)
410              
411             This method is called to dispatch a visitor to the correct method for a
412             filesystem object. In the L class, it calls the
413             visitor L
414             method, passing the C<$self> object reference as an argument.
415              
416             =head2 enter($visitor)
417              
418             This is a custom variant of the L method which is called by a
419             visitor when it first enters a filesystem. Instead of calling the visitor
420             L method, it
421             calls
422             L
423             passing C<$self> as an argument to begin visiting the files and
424             sub-directories contained in this directory.
425              
426             =head1 AUTHOR
427              
428             Andy Wardley L
429              
430             =head1 COPYRIGHT
431              
432             Copyright (C) 2005-2009 Andy Wardley. All rights reserved.
433              
434             =head1 ACKNOWLEDGEMENTS
435              
436             The C modules are built around a number of existing
437             Perl modules, including L, L, L, L,
438             L and draw heavily on ideas in L.
439              
440             Please see the L
441             in L for further information.
442              
443             =head1 SEE ALSO
444              
445             L,
446             L,
447             L,
448             L.
449              
450             =cut
451              
452             # Local Variables:
453             # mode: Perl
454             # perl-indent-level: 4
455             # indent-tabs-mode: nil
456             # End:
457             #
458             # vim: expandtab shiftwidth=4:
459             # TextMate: doesn't need this cruft