Process files lazy

Author: gfldex

You want to recurse over all files in and under a directory in a lazy fashion and stop after the first three files are found. We filter either based on methods of IO::Path or on a simple Str match.

Source code: 09-11-all-files-lazy.p6

#!/usr/bin/env perl6

use v6;

multi sub find-files(Str:D $dir, &filter = {True}) {
    find-files($dir.IO, &filter)
}

multi sub find-files (IO::Path:D $dir, &filter is copy = {True}) {

# If the argument type of &filter is Str, we append a '/' to directories to
# allow simple Str matches against directories.

    my &str-filter = { &filter(.d ?? .Str ~ '/' !! .Str) } if &filter.signature.params[0].type ~~ Str;

    gather for dir($dir) {
        take .IO if (&str-filter ?? str-filter(.IO) !! filter(.IO));
        take slip sort find-files($_, &filter) if .d && (&str-filter ?? str-filter .IO !! filter .IO);
    } but role {

# We mixin a role into the returned Seq to provide one extra method. Calling
# .head would do the same thing but would be less instructive.

        method top(Seq:D: Int $amount){
            my $counter = $amount;
            gather for self {
                take $counter-- ?? $_ !! IterationEnd;
            }
        }
    }
}

sub MAIN(:$dir = "..") {
    my \files = find-files($dir, {
        (.d && .ends-with(none <tmp mnt>) ) # any directory that doesn't end in tmp or mnt
        || .ends-with(any <.pl .md>) # any file or symlink, etc, that end in .pl and .md
    } );

    for files.top(3) -> $path {
        say $path.Str;
    }

    for find-files($dir, -> Str $_ {.ends-with(none <.md 04arrays/>)}) {
        say .d ?? .Str ~ '/' !! .Str;
    }
}