File Coverage

blib/lib/IO/Easy/Dir.pm
Criterion Covered Total %
statement 75 101 74.2
branch 30 48 62.5
condition 15 22 68.1
subroutine 12 17 70.5
pod 10 10 100.0
total 142 198 71.7


line stmt bran cond sub pod time code
1             package IO::Easy::Dir;
2              
3 6     6   33 use Class::Easy;
  6         9  
  6         151  
4              
5 6     6   983 use IO::Easy;
  6         13  
  6         46  
6 6     6   753 use base qw(IO::Easy);
  6         20  
  6         937  
7              
8 6     6   33 use File::Spec;
  6         12  
  6         196  
9             my $FS = 'File::Spec';
10              
11 6     6   34 use Cwd ();
  6         9  
  6         11897  
12              
13             sub current {
14 2     2 1 6 my $pack = shift;
15 2         14940 return $pack->new (Cwd::cwd());
16             }
17              
18             sub home {
19 0     0 1 0 my $pack = shift;
20 0   0     0 return $pack->new (
21             $ENV{USERPROFILE} || $ENV{HOME} || (getpwuid($<)) [7]
22             );
23             }
24              
25             sub create {
26 6     6 1 20 my $self = shift;
27 6         13 my @path = @_;
28            
29 6         91 my $path = $self->{path};
30 6 50       94 if (scalar @path) { # create @path into received directory
31 0         0 $path = File::Spec->catdir ($path, @path);
32             }
33            
34 6         164 my @dirs = File::Spec->splitdir ($path);
35            
36 6         42 foreach my $depth (0 .. scalar @dirs - 1) {
37 16         42 my $dir = File::Spec->join(map {$dirs[$_]} 0..$depth);
  38         225  
38 16 100       766 mkdir $dir
39             unless -d $dir;
40             }
41              
42             }
43              
44             sub type {
45 6     6 1 18 return 'dir';
46             }
47              
48             sub items {
49 8     8 1 13 my $self = shift;
50 8   50     57 my $filter = shift || '';
51 8   50     39 my $is_regexp = shift || 0;
52            
53 8         28 my $path = $self->{path};
54            
55 8 50       24 unless ($is_regexp) {
56 8         25 $filter = join '', '\.', $filter, '$';
57             }
58            
59 8 50       268 opendir (DH, $path) || die "can't open $path: $!";
60 8         18 my @files = ();
61 8         199 foreach my $file_name (readdir (DH)) {
62 24 100       112 next if $file_name =~ /^\.+$/;
63            
64 8 50 33     47 next if $filter ne '\.$' and $file_name !~ /$filter/i;
65            
66 8         29 my $file = $self->append ($file_name);
67            
68 8 50       33 next unless -e $file;
69            
70 8         34 push @files, $file->attach_interface;
71             }
72 8         186 closedir (DH);
73            
74 8         33 return @files;
75             }
76              
77             sub rm_tree {
78 7     7 1 2177 my $self = shift;
79            
80 7         26 my @files = $self->items;
81 7         81 foreach my $file (@files) {
82 5         70 my $path = $file->{path};
83 5 100       463 unlink $path
84             if -f $path;
85 5 100       171 $file->rm_tree
86             if -d $path;
87             }
88            
89 7         1437 rmdir $self->{path};
90             }
91              
92             sub scan_tree {
93 10     10 1 14 my $self = shift;
94 10         14 my $handler = shift;
95            
96 10         15 my $flag = '';
97            
98 10 100       27 if (@_) {
99 2         6 ($handler, $flag) = (shift, $handler);
100             }
101            
102 10         92 my $path = $self->{path};
103            
104 10 50       276 opendir (DH, $path) || die "can't open $path: $!";
105            
106 10         11 my @files;
107            
108 10         390 foreach my $file_name (readdir (DH)) {
109 35 100 100     297 next if $file_name eq $FS->curdir or $file_name eq $FS->updir; # omit . ..
110            
111 15         54 my $file = $self->append ($file_name)->attach_interface;
112            
113 15         46 my $return = 1;
114 15 100 100     201 $return = &$handler ($file)
      100        
115             if ($flag eq 'for_files_only' && -f $file) || $flag ne 'for_files_only';
116            
117 15 100 100     91 push @files, $file
118             if $return || $flag eq 'ignoring_return';
119            
120             }
121 10         133 closedir (DH);
122            
123 10         28 foreach my $file (@files) {
124 11 100       39 if ($file->type eq 'dir') {
    50          
125 6         20 $file->scan_tree ($handler);
126             } elsif ($file->type eq 'file') {
127            
128             }
129             }
130             }
131              
132             sub copy_children {
133 0     0 1 0 my $self = shift;
134 0         0 my $target = shift;
135 0         0 my $handler = shift;
136            
137             $self->scan_tree (sub {
138 0     0   0 my $file = shift;
139            
140 0         0 my $path = $file->rel_path ($self->{path});
141            
142 0 0       0 if (ref $handler eq 'CODE') {
143 0 0       0 next unless &$handler ($file);
144             }
145            
146 0 0       0 if ($file->type eq 'dir') {
147 0         0 $target->create ($path);
148 0         0 return 1;
149             }
150            
151 0         0 $target->append ($path)->as_file->store (
152             $file->contents
153             );
154 0         0 });
155             }
156              
157             sub copy_node {
158 0     0 1 0 my $self = shift;
159 0         0 my $target = shift;
160            
161 0         0 $target->create ($self->name);
162            
163             $self->scan_tree (sub {
164 0     0   0 my $file = shift;
165            
166 0         0 my $path = $file->rel_path ($self->up);
167            
168 0 0       0 if ($file->type eq 'dir') {
169 0         0 $target->create ($path);
170 0         0 return 1;
171             }
172            
173 0         0 $target->append ($path)->as_file->store (
174             $file->contents
175             );
176 0         0 });
177             }
178              
179             sub touch {
180 3     3 1 2000147 my $self = shift;
181            
182 3 100       76 if(-e $self->{path})
183             {
184 2 50       9 if(-d _)
185             {
186 2         5 my $t = time;
187            
188 2 50       88 die "can't utime $self->{path}: $!"
189             unless utime $t, $t, $self->{path};
190             }
191             else
192             {
193 0         0 warn "not a dir: $self->{path}\n";
194             }
195             }
196             else
197             {
198 1 50       79 die "can't create $self->{path}: $!"
199             unless mkdir $self->{path};
200             }
201              
202 3         10 return 1;
203             }
204              
205              
206             1;
207              
208             =head1 NAME
209              
210             IO::Easy::Dir - IO::Easy child class for operations with directories.
211              
212             =head1 SYNOPSIS
213              
214             use IO::Easy;
215              
216             my $dir = IO::Easy->new ('.')->as_dir;
217              
218             $dir->scan_tree (sub {
219             my $file = shift;
220              
221             return 0 if $file->type eq 'dir' and $file->name eq 'CVS';
222             });
223              
224             $dir->create (qw(t IO-Easy)); # creates ./t/IO-Easy
225              
226             my $source = $dir->append('data')->as_dir;
227             my $destination = $dir->append('backup')->as_dir;
228             $source->copy_children($destination, $handler);
229              
230              
231             =head1 METHODS
232              
233             =head2 scan_tree
234              
235             Scans directory tree.
236              
237             There's a standard module File::Find exists. But it's monstrous and is used
238             because of historical reasons. For the same functionality IO::Easy has a
239             method scan_tree and this method can replace File::Find in the most cases.
240              
241             my $io = IO::Easy->new ('.');
242             my $dir = $io->as_dir;
243             $dir->scan_tree ($handler);
244              
245             $handler is a code ref which is called during scan for each found object
246             and retrieves the found object as a parameter.
247              
248             Symlinks processing during directory scanning must be handled by user of this
249             module himself at the moment.
250              
251             As an example with help of $handler you can recursively scan directory and get
252             the number of files with defined extension, in this case function will look like
253             the following:
254              
255             my $counter = 0;
256             my $handler = sub {
257             my $file = shift;
258             $counter++ if $file->extension eq 'pl';
259             }
260              
261             $dir->scan_tree ($handler);
262              
263             print "The number of files/directories with 'pl' extension:", $counter;
264              
265             BEWARE: If $handler returns 0 for the directory, then scan_tree doesn't scan its contents,
266             this can be useful in e.g. ignoring CVS or any other unwanted directories.
267              
268             This method can be called with any of two optional flags:
269             'for_files_only' and 'ignoring_return'
270              
271             For example:
272              
273             my $counter = 0;
274             my $handler = sub {
275             my $file = shift;
276             $counter++ if $file->extension eq 'pl';
277             }
278              
279             $dir->scan_tree (for_files_only => $handler);
280              
281             print "The number of files with 'pl' extension:", $counter;
282              
283             Flag 'for_files_only' tell method to call handler only with objects
284             with file (-f) check
285              
286             Flag 'ignoring_return' tell method to ignore return value from handler
287             and process any found directory
288              
289             =cut
290              
291             =head2 copy_children, copy_node
292              
293             recursive copying of directory contents
294              
295             my $io = IO::Easy->new ('.');
296             my $source = $io->append('data')->as_dir;
297             my $destination = $io->append('backup')->as_dir;
298             $source->copy_children($destination, $handler);
299              
300             In this example $handler code ref, which is performed for every file during copying.
301             With help of the $handler you can easily control the spice which files will be copied.
302              
303             my $handler = sub {
304             my $file = shift;
305             return 1 if $file->extension eq 'txt';
306             return 0;
307             };
308              
309             In this case $handler function copies only files with 'txt' extension to the new
310             directory.
311              
312             =cut
313              
314             =head2 create
315              
316             creates new directory
317              
318             my $io = IO::Easy->new ('.');
319             my $dir = $io->append('data')->as_dir; # appends 'data' to $io and returns
320             #the new object; blesses into directory object.
321             $dir->create; # creates directory './data/'
322              
323             or
324              
325             $io->as_dir->create ('data');
326              
327             =cut
328              
329             =head2 items
330              
331             directory contents in array. you can provide filter for file extension, plain or regexp
332              
333             $dir->items ('txt'); # plain
334             $dir->items ('txt|doc', 1); # regexp
335              
336             =cut
337              
338             =head2 rm_tree
339              
340             recursive deletion directory contents
341              
342             =cut
343              
344             =head2 current
345              
346             current directory constructor, using Cwd
347              
348             =cut
349              
350             =head2 home
351              
352             user home directory
353              
354             =cut
355              
356             =head2 type
357              
358             always 'dir'
359              
360             =head2 touch
361              
362             similar to unix touch command - updates file timestamp
363              
364             =cut
365              
366              
367             =head1 AUTHOR
368              
369             Ivan Baktsheev, C<< >>
370              
371             =head1 BUGS
372              
373             Please report any bugs or feature requests to my email address,
374             or through the web interface at L.
375             I will be notified, and then you'll automatically be notified
376             of progress on your bug as I make changes.
377              
378             =head1 SUPPORT
379              
380              
381              
382             =head1 ACKNOWLEDGEMENTS
383              
384              
385              
386             =head1 COPYRIGHT & LICENSE
387              
388             Copyright 2007-2009 Ivan Baktsheev
389              
390             This program is free software; you can redistribute it and/or modify it
391             under the same terms as Perl itself.
392              
393              
394             =cut