File::Find::Closures

brian_d_foy on 2004-09-30T18:38:10

For a long time I've wanted to create a library of ready-to-use functions to pass to File::Find::find(). I can never remember which File::Find variable is what, and I never have liked the idea that I had to code the accculumation of the filenames if I did not process them immediately. This sorrt of thing seemed like it could use a shot of code reuse mojo.

So I created File::Find::Closures to hold all of those sorts of callbacks. The functions in File::Find::Closures have names like find_by_regex(), and return two things: the callback which I give directly to find(), and a reporter closure that can access the list of files the callback acccumulated.

I thought Andy was going in this direction with File::Find::Wanted, but I think he had something else in mind. Randal came close to what I wanted with File::Finder, but without the re-use.

Maybe this is just one of those things that everyone ends up writing for himself.

So far, Find::Find::Closures is a developer release, so you won't be able to get it through CPAN.pm. It has no prereqs (other than File::Find which it uses in the tests). I've outlined what other people need to do to write their own functions for the module, and hope that people will send me cool ones that I can include.


File::Find::Wanted

petdance on 2004-09-30T19:30:00

All I intended for FFW was to be able to say
my @files = find_wanted( sub { return ! -d $_ }, $startdir );
which would save the calling program from having to build up the list. That's all.

Now, it IS entirely possible that you could have helper functions, like:

sub empty { return -s $_ == 0 }
sub is_dir { return -d $_ }

my @dirs = find_wanted( \&is_dir, $start );

API design

Aristotle on 2004-10-02T12:02:17

The idea is sound, but I'd rather prefer a different interface.

At the very least I'd like to be able to inline the generator call in the find() call, maybe by passing in a reference to where to store the iterator. Actually, that makes it really simple to handle the common case where one simply wants a list of files — just pass an array reference.

my $iter;
File::Find::find( find_by_name( \$iter => qw( README ) ), @directories );
while( my $file = $iter->() ) {
    # ...
}

# or

my @list;
File::Find::find( find_by_name( \@file => qw( README ) ), @directories );
foreach( @file ) {
    # ...
}

But then, F::F::W's interface makes this so much nicer:

my $iter = find_wanted( find_by_name( qw( README ) ), @directories );

my @list = find_wanted( find_by_name( qw( README ) ), @directories );

It would be wicked cool if this was a sufficient reimplementation of File::Find to allow the iterator to actually compute results lazily on demand.

File::Find::Rule could probably trivially be reimplemented by just currying this hypothetical module's closures to compose them, too.

I think you and Andy should join forces here.