### ----------------------------------------------------
### -- Path::Finder
### -- Licenses: Artistic-2.0
### -- Authors: Leon Timmermans
### -- File: lib/Path/Finder.rakumod
### ----------------------------------------------------
### -- Chunk 2 of 2
For example:

 $finder.size(* > 10240)

=head2 Depth rules

 $finder.depth(3..5);

The C<depth> rule method take a single range argument and limits
the paths returned to a minimum or maximum depth (respectively) from the
starting search directory, or an integer representing a specific depth. A depth
of 0 means the starting directory itself.  A depth of 1 means its children.
(This is similar to the Unix C<find> utility.)

=head2 Version control file rules

 # Skip all known VCS files
 $finder.skip-vcs;

Skips files and/or prunes directories related to a version control system.
Just like C<skip-dir>, these rules should be specified early to get the
correct behavior.

=head2 File content rules

=head3 C<contents>

 $finder.contents(rx/BEGIN .* END/);

The C<contents> rule takes a list of regular expressions and returns
files that match one of the expressions.

The expressions are applied to the file's contents as a single string. For
large files, this is likely to take significant time and memory.

Files are assumed to be encoded in UTF-8, but alternative encodings can
be passed as a named argument:

 $finder.contents(rx/BEGIN .* END/xs, :enc<latin1>);

=head3 C<lines>

 $finder.lines(rx:i/^new/);

The C<line> rule takes a list of regular expressions and returns
files with at least one line that matches one of the expressions.

Files are assumed to be encoded in UTF-8, but alternative Perl IO layers can
be passed like in C<contents>

=head3 C<no-lines>

 $finder.no-lines(rx:i/^new/);

The C<line> rule takes a list of regular expressions and returns
files with no lines that matches one of the expressions.

Files are assumed to be encoded in UTF-8, but alternative Perl IO layers can
be passed like in C<contents>

=head3 C<shebang>

 $finder.shebang(rx/#!.*\bperl\b/);

The C<shebang> rule takes a value and checks it against the first line of a
file. The default checks for C<rx/^#!/>.

=head2 Other rules

=head1 EXTENDING

=head2 Custom rule subroutines

Rules are implemented as (usually anonymous) subroutine callbacks that return
a value indicating whether or not the rule matches. These callbacks are called
with three arguments. The only positional argument is a path.

 $finder.and( sub ($item, *%args) { $item ~~ :r & :w & :x } );

The named arguments contain more information for such a check
For example, the C<depth> key is used to support minimum and maximum
depth checks.

The custom rule subroutine must return one of four values:

=item C<True> -- indicates the constraint is satisfied

=item C<False> -- indicates the constraint is not satisfied

=item C<PruneExclusive> -- indicate the constraint is satisfied, and prune if it's a directory

=item C<PruneInclusive> -- indicate the constraint is not satisfied, and prune if it's a directory

Here is an example. This is equivalent to the "depth" rule method with
a depth of C<0..3>:

 $finder.and(
   sub ($path, :$depth, *%) {
     return $depth < 3 ?? True !! PruneExclusive;
   }
 );

Files and directories and directories up to depth 3 will be returned and
directories will be searched. Files of depth 3 will be returned. Directories
of depth 3 will be returned, but their contents will not be added to the
search.

Once a directory is flagged to be pruned, it will be pruned regardless of
subsequent rules.

 $finder.depth(0..3).name(rx/foo/);

This will return files or directories with "foo" in the name, but all
directories at depth 3 will be pruned, regardless of whether they match the
name rule.

Generally, if you want to do directory pruning, you are encouraged to use the
C<skip> method instead of writing your own logic using C<PruneExclusive> and
C<PruneInclusive>.

=head1 PERFORMANCE

By default, C<Path::Finder> iterator options are "slow but safe". They
ensure uniqueness, return files in sorted order, and throw nice error messages
if something goes wrong.

If you want speed over safety, set these options:

 :!loop-safe, :!sorted, :order(PreOrder)

Depending on the file structure being searched, C<< :order(PreOrder) >> may or
may not be a good choice. If you have lots of nested directories and all the
files at the bottom, a depth first search might do less work or use less
memory, particularly if the search will be halted early (e.g. finding the first
N matches.)

Rules will shortcut on failure, so be sure to put rules likely to fail
early in a rule chain.

Consider:

 $f1 = Path::Finder.new.name(rx/foo/).file;
 $f2 = Path::Finder.new.file.name(rx/foo/);

If there are lots of files, but only a few containing "foo", then
C<$f1> above will be faster.

Rules are implemented as code references, so long chains have
some overhead. Consider testing with a custom coderef that
combines several tests into one.

Consider:

 $f3 = Path::Finder.new.read-write-executable;
 $f4 = Path::Finder.new.readable.writeable.executable;

Rule C<$f3> above will be much faster, not only because it stacks
the file tests, but because it requires to only check a single rule.

When using the C<find> function, C<Path::Finder> will try to sort the arguments
automatically in such a way that cheap checks and skipping checks are done first.

=end pod


