Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Interface (Score:2, Informative)

    Yeah, I thought about doing a "nice" version of File::Find myself. I wanted to tie in a few things as well - the ability to get structured data as well as lists from it, and to cache data.

    I'm not sure I like the stream-y interface you've got here - powerful, but violates the KISS principle which makes File::Find such a pain in the arse to use at the moment. I'd pictured more of a hash-based interface, but I hadn't thought of options so much (but I guess they could be done either by regexps or arrays).

    my

    • It was almost the same thing I came up when thinking about it.

      I'd like to see something like this:

      my @files = find('/tmp', { maxdepth => 10, mindepth => 5, name => qr/\.*\.c$/ });

      (Which I btw already have working in a small example I hacked together.) I really like your idea of using arrays for alternation, but how do you decide wheter to AND or OR? (AND doesn't make much sense in your example though).

      Instead of returning the files I'd also consider an 'exec' like option that took a s
      • I've made a quick implementation of what I'd like to see File::Find offer instead. I think it might be a good idea to do a real print function and instead call the one I've used 'return'.

        It is of course not nearly done, but if anyone feel they like the concept and want to use it please feel free to do so.

        package Find;

        use strict;
        use vars qw($VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS @ISA);
        require Exporter;

        @ISA = qw(Exporter);
        @EXPORT = qw(find);
        @EXPORT_OK = qw(find);

        $VERSION = '0.1';

        sub find {
                my $dir = shift || die "Need a directory to start at\n";
                die "Not a directory\n" unless -d $dir || ref($dir) eq 'ARRAY';
                my $opts = shift || {};
                $opts->{print} = defined($opts->{print}) ? $opts->{print} : 1;
                my $depth = 1;
                my @files = ();
                if (ref($dir) eq 'ARRAY') {
                traverse_dir($_, $depth, $opts, \@files) for @{$dir};
                } else {
                traverse_dir($dir, $depth, $opts, \@files);
                }
                return @files;
        }

        sub traverse_dir {
                my $dir_name = shift;
                my $depth = shift;
                my $opts = shift;
                my $files_ref = shift;
                if (defined($opts->{maxdepth}) && $opts->{maxdepth} {_ok} = 1;
                if (defined($opts->{name})) {
                        if ($file !~ /$opts->{name}/) {
                        $opts->{_ok} = 0;
                        }
                }
                if (defined($opts->{mindepth})) {
                        if ($depth {mindepth}) {
                        $opts->{_ok} = 0;
                        }
                }
                if ($opts->{_ok}) {
                        if ($opts->{print}) {
                        push @{$files_ref}, $dir_name . "/" . $file;
                        }
                        if (defined($opts->{'exec'})) {
                                &${$opts->{exec}}($dir_name . "/" . $file);
                        }
                        }
                traverse_dir($dir_name . "/" . $file, $depth + 1, $opts, $files_ref) if -d $dir_name . "/" . $file;
                }
                closedir(DH);
        }

        1;

        __END__

        =head1 NAME

        Find - find files in filesystem

        =head1 SYNOPSIS

                use Find;

                find('/tmp', { 'exec' => \sub { print $_[0] . "\n"; }});

        =head1 OPTIONS

                find('directory', { .. options .. });
                find(['directory1','directory2'], { .. options .. });

                It currently has the following options

        =head2 print

                print in this context refers to wheter or not to return an array of
                the files found.
               
                for (find('/tmp', { 'print' => 1 })) {
                        print $_ . "\n";
                }

                Would print a list of files found in the '/tmp' directory.
                print is set to return a list of files by default.

        =head2 exec

                exec is an anonymous reference to a function to call which gets passed
                as the only argument the filename matching any other conditions.

                find('/tmp', { 'exec' => \sub { print $_[0] . "\n"; } });

        =head2 name

                name is a regular expression to which the file is matched. If the file
                in question matches the file the other tests on the file are performed.

                find('/tmp', { name => qr/\.c$/, 'exec' => \sub { print $_[0] . "\n";} });

        =head2 maxdepth

                maxdepth is the maximum number of directories to descend into.
         
        =head2 mindepth

                mindepth is the minimum number of directories where matching starts.

        =end