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


  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


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.


new( %opts )

Instantiate a new iterator object. %opts may include:


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


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.


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.


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


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.


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.


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".


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.


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


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


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


Returns the root param set in new().


Get/set the param set in new().


Get/set the param set in new().


Get/set the subref used for handling errors.


Get the most recent object error message.


Get/set flag for default error handler.


Returns value set in new().


Get/set subref for manipulating the queue().


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.


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


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.


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


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

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


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


Peter Karman, <>


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.