package Path::Tiny::Glob;
our $AUTHORITY = 'cpan:YANICK';
# ABSTRACT: File globbing utility
$Path::Tiny::Glob::VERSION = '0.2.0';

use strict;
use warnings;

use Path::Tiny;

use Path::Tiny::Glob::Visitor;

use parent 'Exporter::Tiny';

our @EXPORT = qw/ pathglob /;
our @EXPORT_OK = qw/ is_globby /;

use experimental qw/ signatures postderef /;

sub _generate_pathglob {
    my( $class, undef, $args ) = @_;

    return sub(@) { return _pathglob(@_)->all }
        if $args && $args->{all};

    return \&_pathglob;

sub _pathglob( $glob ) {

    my @glob = ref $glob eq 'ARRAY' ? @$glob : ($glob);

    @glob = map {
        ref ? $_ : split '/', $_, -1;
    } @glob;

    my $dir;

    if ( $glob[0] =~ /^~/ ) {
        $dir = path(shift @glob);
    elsif( $glob[0] eq '' ) {
        $dir = Path::Tiny->rootdir;
        shift @glob;
    else {
        $dir = path('.');

    unless( ref $glob[-1] ) {


    return Path::Tiny::Glob::Visitor->new(
        path => $dir,
        globs => [ \@glob ],

sub is_globby($string) {
    return $string =~ /[?*]/;




=encoding UTF-8

=head1 NAME

Path::Tiny::Glob - File globbing utility

=head1 VERSION

version 0.2.0


    use Path::Tiny::Glob;

    my $dzil_files = pathglob( '~/work/perl-modules/**/dist.ini' );

    while( my $file = $dzil_files->next ) {
        say "found a Dist::Zilla project at ", $file->parent;


This module exports a single function by default, C<pathglob>.


=head2 C<pathglob>

    $list = pathglob( $glob );
    $list = pathglob( \@path_segments );

This function takes in
a shell-like file glob, and returns a L<Lazy::List> of L<Path::Tiny> objects
matching it.

If you prefer to get all the globbed files in one go instead of
L<Lazy::List>ed, you can import C<pathglob> with the flag C<all>:

    use Path::Tiny::Glob pathglob => { all => 1 };

    # now behaves like pathglob( '/foo/**' )->all;
    my @files = pathglob( '/foo/**' );

The function can also take an arrayref of path segments.
The segments can be strings, in which case they are obeying
the same globbing patterns as the stringy C<$glob>.

    $list = pathglob( [ 'foo', 'bar', '*', '' ] );

    # equivalent to

    $list = pathglob( 'foo/bar/*/' );

The segments, however, can also be coderefs, which will
be passed  L<Path::Tiny> objects both as their argument and
as C<$_>, and are expected to return C<true> if the path
is matching.

    $big_files = pathglob( [ 'foo/bar/**/', sub { -f $_ and -s $_ > 1E6 } );

The segments can also be regexes, in which case they will be
compared to the paths' current C<basename>.

    @readmes = pathglob( [ 'foo/bar/**/', /^readme\.(md|mkd|txt)$/i );

Known limitation: backtracking paths using C<..> doesn't work.

=head3 Supported globbing patterns


=item C<*>

Matches zero or more characters.

=item C<?>

Matches zero or one character.

=item C<**>

Matches zero or more directories.

If C<**> is the last segment of the path, it'll return
all descendent files.


=head2 C<is_globby>

    my $globby = is_globby( './foo/*/bar' );

Returns C<true> if the argument contains any glob character (so C<?> or C<*>).
Can be useful to determine if the input was an explicit path or a glob.

Not exported by default.

=head1 SEE ALSO


=head1 AUTHOR

Yanick Champoux <>


This software is copyright (c) 2019, 2018 by Yanick Champoux.

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