NAME

Path::Class::Iterator - walk a directory structure

SYNOPSIS

use Path::Class::Iterator;

my $dir = shift @ARGV || '';

my $iterator = Path::Class::Iterator->new(
                      root            => $dir,
                      depth           => 2
                      interesting     => sub { return [sort {"$a" cmp "$b"} @{$_[1]}] }
                      follow_symlinks => 1,
                      follow_hidden   => 0,
                      breadth_first   => 1,
                      show_warnings   => 1
                      );

until ($iterator->done)
{
  my $f = $iterator->next;
  # do something with $f
  # $f is a Path::Class::Dir or Path::Class::File object
}

DESCRIPTION

Path::Class::Iterator walks a directory structure using an iterator. It combines the Iterator closure technique with the magic of Path::Class.

It is similar in idea to Iterator::IO and IO::Dir::Recursive but uses Path::Class objects instead of IO::All objects. It is also similar to the Path::Class::Dir next() method, but automatically acts recursively. In fact, it is similar to many recursive File::Find-type modules, but not quite exactly like them. If it were exactly like them, I wouldn't have written it. I think.

I cribbed much of the Iterator logic directly from Iterator::IO and married it with Path::Class. This module is inspired by hearing Mark Jason Dominus's Higher Order Perl talk at OSCON 2006. Iterator::IO is also inspired by MJD's iterator ideas, but takes it a slightly different direction.

METHODS

new( %opts )

Instantiate a new iterator object. %opts may include:

root

The root directory in which you want to start iterating. This parameter is required.

follow_hidden

Files and directories starting with a dot . are skipped by default. Set this to true to include these hidden items in your iterations.

Symlinks (or whatever returns true with the built-in -l flag on your system) are skipped by default. Set this to true to follow symlinks.

error_handler

A sub ref for handling IO::Dir open() errors. Example would be if you lack permission to a directory. The default handler is to simply skip that directory.

The sub ref should expect 3 arguments: the iterator object, the Path::Class object, and the error message (usually just $!).

The sub ref MUST return a true value or else the iterator will croak.

show_warnings

If set to true (1), the default error handler will print a message on stderr each time it is called.

breadth_first

Iterate over all the contents of a dir before descending into any subdirectories. The default is 0 (depth first), which is similar to File::Find. NOTE: This feature will likely not do what you expect if you also use the interesting() feature.

interesting

A sub ref for manipulating the queue. It should expect 2 arguments: the iterator object and an array ref of Path::Class::Dir objects. It should return an array ref of Path::Class::Dir objects.

This feature implements what MJD calls heuristically guided search.

depth

Do not recurse past n levels. You could also implement the depth feature with interesting, but this is easier. Default is undef (exhaustive recursion).

NOTE: n is calculated relative to root, not the absolute depth of the item. A depth of 1 means do not recurse deeper than root itself, while a depth of 2 means "descend one level below root".

next

Returns the next file or directory from the P::C::I object. The return value will be either a Path::Class::Iterator::File object or Path::Class:Iterator::Dir object. Both object types are subclasses of their respective Path::Class types and inherit all their methods and features, plus a depth() method for getting the depth of the object relative to the root.

NOTE: The depth() method returns the depth of the P::C::I::Dir or P::C::I::File object. See cur_depth() to get the current depth of the P::C::I object.

start

Returns the start time in Epoch seconds that the P::C::I object was first created.

done

Returns true if the P::C::I object has run out of items to iterate over.

iterator

Returns the internal Iterator object. You probably don't want that, but just in case.

root

Returns the root param set in new().

follow_symlinks

Get/set the param set in new().

follow_hidden

Get/set the param set in new().

error_handler

Get/set the subref used for handling errors.

error

Get the most recent object error message.

show_warnings

Get/set flag for default error handler.

breadth_first

Returns value set in new().

interesting

Get/set subref for manipulating the queue().

depth

Get/set the Iterator recursion depth. Default is undef (infinite).

NOTE: This is not the same depth() method as on the return value of next(). This depth() method affects the recursion level for the Iterator object itself.

push_queue->( iterator_object, P::C_object )

Add a Path::Class object to the internal queue. This method is used internally.

pop_queue->( iterator_object )

Remove a Path::Class object from the queue. This method is used internally. Returns the next Path::Class object for iteration, based on breadth_first setting.

queue

Get/set current queue. Value must be an ARRAY ref.

cur_depth

Returns the current Iterator depth relative to root.

CAVEAT: Because of the way the iterator logic works internally, the value of cur_depth() may change after you call next(), so the order you call next() and cur_depth() may create an off-by-1 error in your code if you're not careful. That's because cur_depth() returns the current depth of the Iterator, not the next() value.

my $depth = $iterator->cur_depth;
my $f = $iterator->next;
# $depth == $f->depth()

my $f = $iterator->next;
my $depth = $iterator->cur_depth;
# $depth might not == $f->depth()

It's likely you want to use the depth() method on the return value of next() anyway. See the next() method.

EXAMPLES

See the t/ directory for examples of error_handler() and interesting().

SEE ALSO

Higher Order Perl, Mark Jason Dominus, Morgan Kauffman 2005.

http://perl.plover.com/hop/

Iterator, Iterator::IO, Path::Class, IO::Dir::Recursive, IO::Dir

BUGS

The cur_depth() caveat is a probably a bug, but since we have a depth() method

AUTHOR

Peter Karman, <karman@cpan.org>

COPYRIGHT AND LICENSE

Copyright 2006 by Peter Karman

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.