.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.45) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "Path::Class::Dir 3pm" .TH Path::Class::Dir 3pm 2025-12-14 "perl v5.42.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME Path::Class::Dir \- Objects representing directories .SH VERSION .IX Header "VERSION" version 0.37 .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 1 \& use Path::Class; # Exports dir() by default \& \& my $dir = dir(\*(Aqfoo\*(Aq, \*(Aqbar\*(Aq); # Path::Class::Dir object \& my $dir = Path::Class::Dir\->new(\*(Aqfoo\*(Aq, \*(Aqbar\*(Aq); # Same thing \& \& # Stringifies to \*(Aqfoo/bar\*(Aq on Unix, \*(Aqfoo\ebar\*(Aq on Windows, etc. \& print "dir: $dir\en"; \& \& if ($dir\->is_absolute) { ... } \& if ($dir\->is_relative) { ... } \& \& my $v = $dir\->volume; # Could be \*(AqC:\*(Aq on Windows, empty string \& # on Unix, \*(AqMacintosh HD:\*(Aq on Mac OS \& \& $dir\->cleanup; # Perform logical cleanup of pathname \& $dir\->resolve; # Perform physical cleanup of pathname \& \& my $file = $dir\->file(\*(Aqfile.txt\*(Aq); # A file in this directory \& my $subdir = $dir\->subdir(\*(Aqgeorge\*(Aq); # A subdirectory \& my $parent = $dir\->parent; # The parent directory, \*(Aqfoo\*(Aq \& \& my $abs = $dir\->absolute; # Transform to absolute path \& my $rel = $abs\->relative; # Transform to relative path \& my $rel = $abs\->relative(\*(Aq/foo\*(Aq); # Relative to /foo \& \& print $dir\->as_foreign(\*(AqMac\*(Aq); # :foo:bar: \& print $dir\->as_foreign(\*(AqWin32\*(Aq); # foo\ebar \& \& # Iterate with IO::Dir methods: \& my $handle = $dir\->open; \& while (my $file = $handle\->read) { \& $file = $dir\->file($file); # Turn into Path::Class::File object \& ... \& } \& \& # Iterate with Path::Class methods: \& while (my $file = $dir\->next) { \& # $file is a Path::Class::File or Path::Class::Dir object \& ... \& } .Ve .SH DESCRIPTION .IX Header "DESCRIPTION" The \f(CW\*(C`Path::Class::Dir\*(C'\fR class contains functionality for manipulating directory names in a cross\-platform way. .SH METHODS .IX Header "METHODS" .ie n .IP "$dir = Path::Class::Dir\->new( , , ... )" 4 .el .IP "\f(CW$dir\fR = Path::Class::Dir\->new( , , ... )" 4 .IX Item "$dir = Path::Class::Dir->new( , , ... )" .PD 0 .ie n .IP "$dir = dir( , , ... )" 4 .el .IP "\f(CW$dir\fR = dir( , , ... )" 4 .IX Item "$dir = dir( , , ... )" .PD Creates a new \f(CW\*(C`Path::Class::Dir\*(C'\fR object and returns it. The arguments specify names of directories which will be joined to create a single directory object. A volume may also be specified as the first argument, or as part of the first argument. You can use platform\-neutral syntax: .Sp .Vb 1 \& my $dir = dir( \*(Aqfoo\*(Aq, \*(Aqbar\*(Aq, \*(Aqbaz\*(Aq ); .Ve .Sp or platform\-native syntax: .Sp .Vb 1 \& my $dir = dir( \*(Aqfoo/bar/baz\*(Aq ); .Ve .Sp or a mixture of the two: .Sp .Vb 1 \& my $dir = dir( \*(Aqfoo/bar\*(Aq, \*(Aqbaz\*(Aq ); .Ve .Sp All three of the above examples create relative paths. To create an absolute path, either use the platform native syntax for doing so: .Sp .Vb 1 \& my $dir = dir( \*(Aq/var/tmp\*(Aq ); .Ve .Sp or use an empty string as the first argument: .Sp .Vb 1 \& my $dir = dir( \*(Aq\*(Aq, \*(Aqvar\*(Aq, \*(Aqtmp\*(Aq ); .Ve .Sp If the second form seems awkward, that\*(Aqs somewhat intentional \- paths like \f(CW\*(C`/var/tmp\*(C'\fR or \f(CW\*(C`\eWindows\*(C'\fR aren\*(Aqt cross\-platform concepts in the first place (many non\-Unix platforms don\*(Aqt have a notion of a "root directory"), so they probably shouldn\*(Aqt appear in your code if you\*(Aqre trying to be cross\-platform. The first form is perfectly natural, because paths like this may come from config files, user input, or whatever. .Sp As a special case, since it doesn\*(Aqt otherwise mean anything useful and it\*(Aqs convenient to define this way, \f(CW\*(C`Path::Class::Dir\->new()\*(C'\fR (or \&\f(CWdir()\fR) refers to the current directory (\f(CW\*(C`File::Spec\->curdir\*(C'\fR). To get the current directory as an absolute path, do \f(CW\*(C`dir()\->absolute\*(C'\fR. .Sp Finally, as another special case \f(CWdir(undef)\fR will return undef, since that\*(Aqs usually an accident on the part of the caller, and returning the root directory would be a nasty surprise just asking for trouble a few lines later. .ie n .IP $dir\->stringify 4 .el .IP \f(CW$dir\fR\->stringify 4 .IX Item "$dir->stringify" This method is called internally when a \f(CW\*(C`Path::Class::Dir\*(C'\fR object is used in a string context, so the following are equivalent: .Sp .Vb 2 \& $string = $dir\->stringify; \& $string = "$dir"; .Ve .ie n .IP $dir\->volume 4 .el .IP \f(CW$dir\fR\->volume 4 .IX Item "$dir->volume" Returns the volume (e.g. \f(CW\*(C`C:\*(C'\fR on Windows, \f(CW\*(C`Macintosh HD:\*(C'\fR on Mac OS, etc.) of the directory object, if any. Otherwise, returns the empty string. .ie n .IP $dir\->basename 4 .el .IP \f(CW$dir\fR\->basename 4 .IX Item "$dir->basename" Returns the last directory name of the path as a string. .ie n .IP $dir\->is_dir 4 .el .IP \f(CW$dir\fR\->is_dir 4 .IX Item "$dir->is_dir" Returns a boolean value indicating whether this object represents a directory. Not surprisingly, Path::Class::File objects always return false, and \f(CW\*(C`Path::Class::Dir\*(C'\fR objects always return true. .ie n .IP $dir\->is_absolute 4 .el .IP \f(CW$dir\fR\->is_absolute 4 .IX Item "$dir->is_absolute" Returns true or false depending on whether the directory refers to an absolute path specifier (like \f(CW\*(C`/usr/local\*(C'\fR or \f(CW\*(C`\eWindows\*(C'\fR). .ie n .IP $dir\->is_relative 4 .el .IP \f(CW$dir\fR\->is_relative 4 .IX Item "$dir->is_relative" Returns true or false depending on whether the directory refers to a relative path specifier (like \f(CW\*(C`lib/foo\*(C'\fR or \f(CW\*(C`./dir\*(C'\fR). .ie n .IP $dir\->cleanup 4 .el .IP \f(CW$dir\fR\->cleanup 4 .IX Item "$dir->cleanup" Performs a logical cleanup of the file path. For instance: .Sp .Vb 2 \& my $dir = dir(\*(Aq/foo//baz/./foo\*(Aq)\->cleanup; \& # $dir now represents \*(Aq/foo/baz/foo\*(Aq; .Ve .ie n .IP $dir\->resolve 4 .el .IP \f(CW$dir\fR\->resolve 4 .IX Item "$dir->resolve" Performs a physical cleanup of the file path. For instance: .Sp .Vb 2 \& my $dir = dir(\*(Aq/foo//baz/../foo\*(Aq)\->resolve; \& # $dir now represents \*(Aq/foo/foo\*(Aq, assuming no symlinks .Ve .Sp This actually consults the filesystem to verify the validity of the path. .ie n .IP "$file = $dir\->file( , , ..., )" 4 .el .IP "\f(CW$file\fR = \f(CW$dir\fR\->file( , , ..., )" 4 .IX Item "$file = $dir->file( , , ..., )" Returns a Path::Class::File object representing an entry in \f(CW$dir\fR or one of its subdirectories. Internally, this just calls \f(CW\*(C`Path::Class::File\->new( @_ )\*(C'\fR. .ie n .IP "$subdir = $dir\->subdir( , , ... )" 4 .el .IP "\f(CW$subdir\fR = \f(CW$dir\fR\->subdir( , , ... )" 4 .IX Item "$subdir = $dir->subdir( , , ... )" Returns a new \f(CW\*(C`Path::Class::Dir\*(C'\fR object representing a subdirectory of \f(CW$dir\fR. .ie n .IP "$parent = $dir\->parent" 4 .el .IP "\f(CW$parent\fR = \f(CW$dir\fR\->parent" 4 .IX Item "$parent = $dir->parent" Returns the parent directory of \f(CW$dir\fR. Note that this is the \&\fIlogical\fR parent, not necessarily the physical parent. It really means we just chop off entries from the end of the directory list until we cain\*(Aqt chop no more. If the directory is relative, we start using the relative forms of parent directories. .Sp The following code demonstrates the behavior on absolute and relative directories: .Sp .Vb 5 \& $dir = dir(\*(Aq/foo/bar\*(Aq); \& for (1..6) { \& print "Absolute: $dir\en"; \& $dir = $dir\->parent; \& } \& \& $dir = dir(\*(Aqfoo/bar\*(Aq); \& for (1..6) { \& print "Relative: $dir\en"; \& $dir = $dir\->parent; \& } \& \& ########### Output on Unix ################ \& Absolute: /foo/bar \& Absolute: /foo \& Absolute: / \& Absolute: / \& Absolute: / \& Absolute: / \& Relative: foo/bar \& Relative: foo \& Relative: . \& Relative: .. \& Relative: ../.. \& Relative: ../../.. .Ve .ie n .IP "@list = $dir\->children" 4 .el .IP "\f(CW@list\fR = \f(CW$dir\fR\->children" 4 .IX Item "@list = $dir->children" Returns a list of Path::Class::File and/or \f(CW\*(C`Path::Class::Dir\*(C'\fR objects listed in this directory, or in scalar context the number of such objects. Obviously, it is necessary for \f(CW$dir\fR to exist and be readable in order to find its children. .Sp Note that the children are returned as subdirectories of \f(CW$dir\fR, i.e. the children of \fIfoo\fR will be \fIfoo/bar\fR and \fIfoo/baz\fR, not \&\fIbar\fR and \fIbaz\fR. .Sp Ordinarily \f(CWchildren()\fR will not include the \fIself\fR and \fIparent\fR entries \f(CW\*(C`.\*(C'\fR and \f(CW\*(C`..\*(C'\fR (or their equivalents on non\-Unix systems), because that\*(Aqs like I\*(Aqm\-my\-own\-grandpa business. If you do want all directory entries including these special ones, pass a true value for the \f(CW\*(C`all\*(C'\fR parameter: .Sp .Vb 2 \& @c = $dir\->children(); # Just the children \& @c = $dir\->children(all => 1); # All entries .Ve .Sp In addition, there\*(Aqs a \f(CW\*(C`no_hidden\*(C'\fR parameter that will exclude all normally "hidden" entries \- on Unix this means excluding all entries that begin with a dot (\f(CW\*(C`.\*(C'\fR): .Sp .Vb 1 \& @c = $dir\->children(no_hidden => 1); # Just normally\-visible entries .Ve .ie n .IP "$abs = $dir\->absolute" 4 .el .IP "\f(CW$abs\fR = \f(CW$dir\fR\->absolute" 4 .IX Item "$abs = $dir->absolute" Returns a \f(CW\*(C`Path::Class::Dir\*(C'\fR object representing \f(CW$dir\fR as an absolute path. An optional argument, given as either a string or a \&\f(CW\*(C`Path::Class::Dir\*(C'\fR object, specifies the directory to use as the base of relativity \- otherwise the current working directory will be used. .ie n .IP "$rel = $dir\->relative" 4 .el .IP "\f(CW$rel\fR = \f(CW$dir\fR\->relative" 4 .IX Item "$rel = $dir->relative" Returns a \f(CW\*(C`Path::Class::Dir\*(C'\fR object representing \f(CW$dir\fR as a relative path. An optional argument, given as either a string or a \&\f(CW\*(C`Path::Class::Dir\*(C'\fR object, specifies the directory to use as the base of relativity \- otherwise the current working directory will be used. .ie n .IP "$boolean = $dir\->subsumes($other)" 4 .el .IP "\f(CW$boolean\fR = \f(CW$dir\fR\->subsumes($other)" 4 .IX Item "$boolean = $dir->subsumes($other)" Returns true if this directory spec subsumes the other spec, and false otherwise. Think of "subsumes" as "contains", but we only look at the \&\fIspecs\fR, not whether \f(CW$dir\fR actually contains \f(CW$other\fR on the filesystem. .Sp The \f(CW$other\fR argument may be a \f(CW\*(C`Path::Class::Dir\*(C'\fR object, a Path::Class::File object, or a string. In the latter case, we assume it\*(Aqs a directory. .Sp .Vb 7 \& # Examples: \& dir(\*(Aqfoo/bar\*(Aq )\->subsumes(dir(\*(Aqfoo/bar/baz\*(Aq)) # True \& dir(\*(Aq/foo/bar\*(Aq)\->subsumes(dir(\*(Aq/foo/bar/baz\*(Aq)) # True \& dir(\*(Aqfoo/..\*(Aq)\->subsumes(dir(\*(Aqfoo/../bar)) # True \& dir(\*(Aqfoo/bar\*(Aq )\->subsumes(dir(\*(Aqbar/baz\*(Aq)) # False \& dir(\*(Aq/foo/bar\*(Aq)\->subsumes(dir(\*(Aqfoo/bar\*(Aq)) # False \& dir(\*(Aqfoo/..\*(Aq)\->subsumes(dir(\*(Aqbar\*(Aq)) # False! Use C to resolve ".." .Ve .ie n .IP "$boolean = $dir\->contains($other)" 4 .el .IP "\f(CW$boolean\fR = \f(CW$dir\fR\->contains($other)" 4 .IX Item "$boolean = $dir->contains($other)" Returns true if this directory actually contains \f(CW$other\fR on the filesystem. \f(CW$other\fR doesn\*(Aqt have to be a direct child of \f(CW$dir\fR, it just has to be subsumed after both paths have been resolved. .ie n .IP "$foreign = $dir\->as_foreign($type)" 4 .el .IP "\f(CW$foreign\fR = \f(CW$dir\fR\->as_foreign($type)" 4 .IX Item "$foreign = $dir->as_foreign($type)" Returns a \f(CW\*(C`Path::Class::Dir\*(C'\fR object representing \f(CW$dir\fR as it would be specified on a system of type \f(CW$type\fR. Known types include \&\f(CW\*(C`Unix\*(C'\fR, \f(CW\*(C`Win32\*(C'\fR, \f(CW\*(C`Mac\*(C'\fR, \f(CW\*(C`VMS\*(C'\fR, and \f(CW\*(C`OS2\*(C'\fR, i.e. anything for which there is a subclass of \f(CW\*(C`File::Spec\*(C'\fR. .Sp Any generated objects (subdirectories, files, parents, etc.) will also retain this type. .ie n .IP "$foreign = Path::Class::Dir\->new_foreign($type, @args)" 4 .el .IP "\f(CW$foreign\fR = Path::Class::Dir\->new_foreign($type, \f(CW@args\fR)" 4 .IX Item "$foreign = Path::Class::Dir->new_foreign($type, @args)" Returns a \f(CW\*(C`Path::Class::Dir\*(C'\fR object representing \f(CW$dir\fR as it would be specified on a system of type \f(CW$type\fR. Known types include \&\f(CW\*(C`Unix\*(C'\fR, \f(CW\*(C`Win32\*(C'\fR, \f(CW\*(C`Mac\*(C'\fR, \f(CW\*(C`VMS\*(C'\fR, and \f(CW\*(C`OS2\*(C'\fR, i.e. anything for which there is a subclass of \f(CW\*(C`File::Spec\*(C'\fR. .Sp The arguments in \f(CW@args\fR are the same as they would be specified in \&\f(CWnew()\fR. .ie n .IP "@list = $dir\->dir_list([OFFSET, [LENGTH]])" 4 .el .IP "\f(CW@list\fR = \f(CW$dir\fR\->dir_list([OFFSET, [LENGTH]])" 4 .IX Item "@list = $dir->dir_list([OFFSET, [LENGTH]])" Returns the list of strings internally representing this directory structure. Each successive member of the list is understood to be an entry in its predecessor\*(Aqs directory list. By contract, \f(CW\*(C`Path::Class\->new( $dir\->dir_list )\*(C'\fR should be equivalent to \f(CW$dir\fR. .Sp The semantics of this method are similar to Perl\*(Aqs \f(CW\*(C`splice\*(C'\fR or \&\f(CW\*(C`substr\*(C'\fR functions; they return \f(CW\*(C`LENGTH\*(C'\fR elements starting at \&\f(CW\*(C`OFFSET\*(C'\fR. If \f(CW\*(C`LENGTH\*(C'\fR is omitted, returns all the elements starting at \f(CW\*(C`OFFSET\*(C'\fR up to the end of the list. If \f(CW\*(C`LENGTH\*(C'\fR is negative, returns the elements from \f(CW\*(C`OFFSET\*(C'\fR onward except for \f(CW\*(C`\-LENGTH\*(C'\fR elements at the end. If \f(CW\*(C`OFFSET\*(C'\fR is negative, it counts backward \&\f(CW\*(C`OFFSET\*(C'\fR elements from the end of the list. If \f(CW\*(C`OFFSET\*(C'\fR and \&\f(CW\*(C`LENGTH\*(C'\fR are both omitted, the entire list is returned. .Sp In a scalar context, \f(CWdir_list()\fR with no arguments returns the number of entries in the directory list; \f(CWdir_list(OFFSET)\fR returns the single element at that offset; \f(CW\*(C`dir_list(OFFSET, LENGTH)\*(C'\fR returns the final element that would have been returned in a list context. .ie n .IP $dir\->components 4 .el .IP \f(CW$dir\fR\->components 4 .IX Item "$dir->components" Identical to \f(CWdir_list()\fR. It exists because there\*(Aqs an analogous method \f(CWdir_list()\fR in the \f(CW\*(C`Path::Class::File\*(C'\fR class that also returns the basename string, so this method lets someone call \&\f(CWcomponents()\fR without caring whether the object is a file or a directory. .ie n .IP "$fh = $dir\->\fBopen()\fR" 4 .el .IP "\f(CW$fh\fR = \f(CW$dir\fR\->\fBopen()\fR" 4 .IX Item "$fh = $dir->open()" Passes \f(CW$dir\fR to \f(CW\*(C`IO::Dir\->open\*(C'\fR and returns the result as an IO::Dir object. If the opening fails, \f(CW\*(C`undef\*(C'\fR is returned and \&\f(CW$!\fR is set. .ie n .IP "$dir\->mkpath($verbose, $mode)" 4 .el .IP "\f(CW$dir\fR\->mkpath($verbose, \f(CW$mode\fR)" 4 .IX Item "$dir->mkpath($verbose, $mode)" Passes all arguments, including \f(CW$dir\fR, to \f(CWFile::Path::mkpath()\fR and returns the result (a list of all directories created). .ie n .IP "$dir\->rmtree($verbose, $cautious)" 4 .el .IP "\f(CW$dir\fR\->rmtree($verbose, \f(CW$cautious\fR)" 4 .IX Item "$dir->rmtree($verbose, $cautious)" Passes all arguments, including \f(CW$dir\fR, to \f(CWFile::Path::rmtree()\fR and returns the result (the number of files successfully deleted). .ie n .IP $dir\->\fBremove()\fR 4 .el .IP \f(CW$dir\fR\->\fBremove()\fR 4 .IX Item "$dir->remove()" Removes the directory, which must be empty. Returns a boolean value indicating whether or not the directory was successfully removed. This method is mainly provided for consistency with \&\f(CW\*(C`Path::Class::File\*(C'\fR\*(Aqs \f(CWremove()\fR method. .ie n .IP $dir\->tempfile(...) 4 .el .IP \f(CW$dir\fR\->tempfile(...) 4 .IX Item "$dir->tempfile(...)" An interface to File::Temp\*(Aqs \f(CWtempfile()\fR function. Just like that function, if you call this in a scalar context, the return value is the filehandle and the file is \f(CW\*(C`unlink\*(C'\fRed as soon as possible (which is immediately on Unix\-like platforms). If called in a list context, the return values are the filehandle and the filename. .Sp The given directory is passed as the \f(CW\*(C`DIR\*(C'\fR parameter. .Sp Here\*(Aqs an example of pretty good usage which doesn\*(Aqt allow race conditions, won\*(Aqt leave yucky tempfiles around on your filesystem, etc.: .Sp .Vb 4 \& my $fh = $dir\->tempfile; \& print $fh "Here\*(Aqs some data...\en"; \& seek($fh, 0, 0); \& while (<$fh>) { do something... } .Ve .Sp Or in combination with a \f(CW\*(C`fork\*(C'\fR: .Sp .Vb 8 \& my $fh = $dir\->tempfile; \& print $fh "Here\*(Aqs some more data...\en"; \& seek($fh, 0, 0); \& if ($pid=fork()) { \& wait; \& } else { \& something($_) while <$fh>; \& } .Ve .ie n .IP "$dir_or_file = $dir\->\fBnext()\fR" 4 .el .IP "\f(CW$dir_or_file\fR = \f(CW$dir\fR\->\fBnext()\fR" 4 .IX Item "$dir_or_file = $dir->next()" A convenient way to iterate through directory contents. The first time \f(CWnext()\fR is called, it will \f(CWopen()\fR the directory and read the first item from it, returning the result as a \f(CW\*(C`Path::Class::Dir\*(C'\fR or Path::Class::File object (depending, of course, on its actual type). Each subsequent call to \f(CWnext()\fR will simply iterate over the directory\*(Aqs contents, until there are no more items in the directory, and then the undefined value is returned. For example, to iterate over all the regular files in a directory: .Sp .Vb 5 \& while (my $file = $dir\->next) { \& next unless \-f $file; \& my $fh = $file\->open(\*(Aqr\*(Aq) or die "Can\*(Aqt read $file: $!"; \& ... \& } .Ve .Sp If an error occurs when opening the directory (for instance, it doesn\*(Aqt exist or isn\*(Aqt readable), \f(CWnext()\fR will throw an exception with the value of \f(CW$!\fR. .ie n .IP "$dir\->traverse( sub { ... }, @args )" 4 .el .IP "\f(CW$dir\fR\->traverse( sub { ... }, \f(CW@args\fR )" 4 .IX Item "$dir->traverse( sub { ... }, @args )" Calls the given callback for the root, passing it a continuation function which, when called, will call this recursively on each of its children. The callback function should be of the form: .Sp .Vb 4 \& sub { \& my ($child, $cont, @args) = @_; \& # ... \& } .Ve .Sp For instance, to calculate the number of files in a directory, you can do this: .Sp .Vb 4 \& my $nfiles = $dir\->traverse(sub { \& my ($child, $cont) = @_; \& return sum($cont\->(), ($child\->is_dir ? 0 : 1)); \& }); .Ve .Sp or to calculate the maximum depth of a directory: .Sp .Vb 4 \& my $depth = $dir\->traverse(sub { \& my ($child, $cont, $depth) = @_; \& return max($cont\->($depth + 1), $depth); \& }, 0); .Ve .Sp You can also choose not to call the callback in certain situations: .Sp .Vb 6 \& $dir\->traverse(sub { \& my ($child, $cont) = @_; \& return if \-l $child; # don\*(Aqt follow symlinks \& # do something with $child \& return $cont\->(); \& }); .Ve .ie n .IP "$dir\->traverse_if( sub { ... }, sub { ... }, @args )" 4 .el .IP "\f(CW$dir\fR\->traverse_if( sub { ... }, sub { ... }, \f(CW@args\fR )" 4 .IX Item "$dir->traverse_if( sub { ... }, sub { ... }, @args )" traverse with additional "should I visit this child" callback. Particularly useful in case examined tree contains inaccessible directories. .Sp Canonical example: .Sp .Vb 11 \& $dir\->traverse_if( \& sub { \& my ($child, $cont) = @_; \& # do something with $child \& return $cont\->(); \& }, \& sub { \& my ($child) = @_; \& # Process only readable items \& return \-r $child; \& }); .Ve .Sp Second callback gets single parameter: child. Only children for which it returns true will be processed by the first callback. .Sp Remaining parameters are interpreted as in traverse, in particular \&\f(CW\*(C`traverse_if(callback, sub { 1 }, @args\*(C'\fR is equivalent to \&\f(CW\*(C`traverse(callback, @args)\*(C'\fR. .ie n .IP "$dir\->recurse( callback => sub {...} )" 4 .el .IP "\f(CW$dir\fR\->recurse( callback => sub {...} )" 4 .IX Item "$dir->recurse( callback => sub {...} )" Iterates through this directory and all of its children, and all of its children\*(Aqs children, etc., calling the \f(CW\*(C`callback\*(C'\fR subroutine for each entry. This is a lot like what the File::Find module does, and of course \f(CW\*(C`File::Find\*(C'\fR will work fine on Path::Class objects, but the advantage of the \f(CWrecurse()\fR method is that it will also feed your callback routine \f(CW\*(C`Path::Class\*(C'\fR objects rather than just pathname strings. .Sp The \f(CWrecurse()\fR method requires a \f(CW\*(C`callback\*(C'\fR parameter specifying the subroutine to invoke for each entry. It will be passed the \&\f(CW\*(C`Path::Class\*(C'\fR object as its first argument. .Sp \&\f(CWrecurse()\fR also accepts two boolean parameters, \f(CW\*(C`depthfirst\*(C'\fR and \&\f(CW\*(C`preorder\*(C'\fR that control the order of recursion. The default is a preorder, breadth\-first search, i.e. \f(CW\*(C`depthfirst => 0, preorder => 1\*(C'\fR. At the time of this writing, all combinations of these two parameters are supported \fIexcept\fR \f(CW\*(C`depthfirst => 0, preorder => 0\*(C'\fR. .Sp \&\f(CW\*(C`callback\*(C'\fR is normally not required to return any value. If it returns special constant \f(CWPath::Class::Entity::PRUNE()\fR (more easily available as \f(CW\*(C`$item\->PRUNE\*(C'\fR), no children of analyzed item will be analyzed (mostly as if you set \f(CW\*(C`$File::Find::prune=1\*(C'\fR). Of course pruning is available only in \f(CW\*(C`preorder\*(C'\fR, in postorder return value has no effect. .ie n .IP "$st = $file\->\fBstat()\fR" 4 .el .IP "\f(CW$st\fR = \f(CW$file\fR\->\fBstat()\fR" 4 .IX Item "$st = $file->stat()" Invokes \f(CWFile::stat::stat()\fR on this directory and returns a \&\f(CW\*(C`File::stat\*(C'\fR object representing the result. .ie n .IP "$st = $file\->\fBlstat()\fR" 4 .el .IP "\f(CW$st\fR = \f(CW$file\fR\->\fBlstat()\fR" 4 .IX Item "$st = $file->lstat()" Same as \f(CWstat()\fR, but if \f(CW$file\fR is a symbolic link, \f(CWlstat()\fR stats the link instead of the directory the link points to. .ie n .IP "$class = $file\->\fBfile_class()\fR" 4 .el .IP "\f(CW$class\fR = \f(CW$file\fR\->\fBfile_class()\fR" 4 .IX Item "$class = $file->file_class()" Returns the class which should be used to create file objects. .Sp Generally overridden whenever this class is subclassed. .SH AUTHOR .IX Header "AUTHOR" Ken Williams, kwilliams@cpan.org .SH "SEE ALSO" .IX Header "SEE ALSO" Path::Class, Path::Class::File, File::Spec