File Coverage

blib/lib/File/Find/Iterator.pm
Criterion Covered Total %
statement 76 81 93.8
branch 22 28 78.5
condition 8 12 66.6
subroutine 15 17 88.2
pod 2 3 66.6
total 123 141 87.2


line stmt bran cond sub pod time code
1             package File::Find::Iterator;
2              
3              
4             # Copyright (c) 2003 Robert Silve
5             # All rights reserved.
6             # This program is free software; you can redistribute it and/or modify it
7             # under the same terms as Perl itself.
8              
9             require Exporter;
10 2     2   80758 use Class::Iterator qw(igrep imap);
  2         5038  
  2         169  
11 2     2   17 use Carp;
  2         4  
  2         443  
12 2     2   4515 use IO::Dir;
  2         142710  
  2         187  
13 2     2   2927 use Storable;
  2         17755  
  2         177  
14 2     2   21 use vars qw($VERSION @ISA @EXPORT);
  2         5  
  2         2996  
15             @ISA = qw(Exporter Class::Iterator);
16             @EXPORT = qw(imap igrep);
17              
18             $VERSION = "0.4";
19              
20             sub walktree {
21 7     7 0 29 my ($opt, @TODO) = @_;
22 7         35 my %opt = %$opt;
23              
24             return sub {
25              
26 259 100 100 259   18539 if ($opt{statefile} && -e $opt{statefile} ) {
27 46   33     144 my $rTODO = retrieve($opt{statefile}) ||
28             croak "Can't retrieve from $opt{statefile} : $!\n";
29 46         4582 @TODO = @$rTODO;
30             }
31            
32 259 100       694 return unless @TODO;
33 253         372 my $item = pop @TODO;
34 253         787 $item =~ s%/+$%%;
35 253 100       4180 if (-d $item ) {
36 127         6128 my $d = IO::Dir->new($item);
37 127         7393 while (defined($_ = $d->read)) {
38 512 100 100     6324 next if ($_ eq '.' || $_ eq '..');
39 258         996 push @TODO, "$item/$_";
40             }
41             }
42              
43 253 50       5271 if ($opt{order}) {
44 0         0 @TODO = sort {$opt{order}->($a,$b)} @TODO;
  0         0  
45             }
46 253 100       496 if ($opt{statefile}) {
47 46 50       154 store(\@TODO, $opt{statefile}) ||
48             croak "Can't store to $opt{statefile} : $!\n";
49             }
50            
51 253         12414 return $item;
52             }
53 7         84 }
54              
55              
56              
57             sub create {
58 3     3 1 347 my $proto = shift;
59 3   33     67 my $class = ref($proto) || $proto;
60 3         15 my %args = @_;
61            
62             my $gen_code = sub {
63 3         13 walktree({statefile => $args{statefile},
64             order => $args{order} } ,
65 3     3   111 @{$args{dir}})
66 3         17 };
67            
68 3         34 my $self = $class->SUPER::new($gen_code);
69 3 50   0   38 $self = igrep { $args{filter}->() } $self if $args{filter};
  0         0  
70 3 50   0   25 $self = imap { $args{map}->() } $self if $args{map};
  0         0  
71 3         10 map { $self->{$_} = $args{$_} } keys %args;
  3         12  
72 3         12 return $self;
73             }
74              
75              
76              
77             sub first {
78 4     4 1 379 my $self = shift;
79             my $gen_code = sub {
80 4         24 walktree({statefile => $self->statefile,
81             order => $self->order } ,
82 4     4   55 @{$self->dir})
83 4         21 };
84 4         29 $self->generator($gen_code);
85 4         54 $self->init;
86 4 100   41   109 my $oo = igrep { $self->filter->() } $self if $self->filter;
  41         204  
87 4         90 map { $self->{$_} = $oo->{$_} } keys %{$oo};
  4         10  
  4         14  
88 4 100   1   43 my $oo2 = imap { $self->map->() } $self if $self->map;
  1         22  
89 4         45 map { $self->{$_} = $oo2->{$_} } keys %{$oo2};
  2         11  
  4         43  
90             }
91              
92              
93             sub AUTOLOAD {
94 10     10   14039 my ($self) = @_;
95 10         61 my ($pack, $meth) =($AUTOLOAD =~ /^(.*)::(.*)$/);
96 10 50       33 return if $meth eq 'DESTROY';
97 10         39 my @auth = qw(dir filter map statefile order);
98 10         19 my %auth = map { $_ => 1 } @auth;
  50         106  
99              
100 10 50       32 unless ($auth{$meth}) {
101 0         0 croak "Unknow method $meth";
102             }
103            
104             my $code = sub {
105 66     66   1235 my $self = shift;
106 66         99 my $arg = shift;
107 66 100       126 if ($arg) {
108 3         21 $self->{$meth} = $arg;
109             } else {
110 63         614 return $self->{$meth};
111             }
112 10         51 };
113            
114 10         44 *$AUTOLOAD = $code;
115 10         52 goto &$AUTOLOAD;
116            
117             }
118              
119             1;
120              
121              
122             __END__
123             # Below is stub documentation for your module. You better edit it!
124              
125             =head1 NAME
126              
127             Find::File::Iterator - Iterator interface for search files
128              
129             =head1 SYNOPSIS
130              
131             use File::Find::Iterator;
132             my $find = File::Find::Iterator->create(dir => ["/home", "/var"],
133             filter => \&isdir);
134             sub isdir { -d }
135              
136             while (my $f = $find->next) { print "file : $f\n" }
137            
138             #reread with different filter
139             $find->filter(\&ishtml);
140             $find->first;
141             while (my $f = $find->next) { print "file : $f\n" }
142              
143             sub ishtml { /\.html?$/ }
144              
145             # using file for storing state
146             $find->statefile($statefile);
147             $find->first;
148             # this time it could crash
149             while (my $f = $find->next)
150             { print "file : $f\n" }
151              
152             # using imap and igrep
153             use File::Find::Iterator qw(imap igrep);
154             my $find = File::Find::Iterator->new(dir => ["/home", "/var"]);
155             $find = imap { -M } igrep { -d } $find;
156              
157             =head1 DESCRIPTION
158              
159             Find::File::Iterator is an iterator object for searching through directory
160             trees. You can easily run filter on each file name. You can easily save the
161             search state when you want to stop the search and continue the same search
162             later.
163              
164             Find::File::Iterator inherited from L<Class::Iterator> so you can use the
165             imap and the igrep constructor.
166              
167             =over 4
168              
169             =item create(%opt)
170              
171             This is the constructor. The C<%opt> accept the following key :
172              
173             =over 4
174              
175             =item dir C<< => \@dir >>
176              
177             which take a reference to a list of directory.
178              
179             =item filter C<< => \&code >>
180              
181             which take a code reference
182              
183             =item statefile C<< => $file >>
184              
185             which take a filename
186              
187             =back
188              
189             =item next
190              
191             calling this method make one iteration. It return file name or
192             C<undef> if there is no more work to do.
193              
194             =item first
195              
196             calling this method make an initialisation of the iterator.
197             You can use it for do a search again, but with some little
198             change (directory root, statefile option, different filter).
199              
200             =item dir([ \@dir ])
201              
202             this method get or set the directory list for the search.
203              
204             =item filter([ \&code ])
205              
206             this method get or set the filter method use by C<next> method.
207              
208             =item statefile([ $file ])
209              
210             this method get or set the name of the file use for store state of the
211             search (see L</"STORING STATE">).
212              
213             =back
214              
215              
216              
217             =head1 STORING STATE
218              
219             If the option C<statefile> of the constructor or the C<statefile> field
220             of the object is set, the iterator use the L<Storable> module to record
221             is internal state after one iteration and to set is internal state before
222             a new iteration. With this mechanism you can continue your search after
223             an error occurred.
224              
225             =head1 SEE ALSO
226              
227             L<Class::Iterator>
228              
229             =head1 CREDITS
230              
231             Marc Jason Dominius's YAPC::EU 2003 classes.
232              
233             =head1 AUTHOR
234              
235             Robert Silve <robert@silve.net>
236              
237             =cut