File Coverage

blib/lib/Path/Tiny/Glob/Visitor.pm
Criterion Covered Total %
statement 51 51 100.0
branch 8 8 100.0
condition n/a
subroutine 8 8 100.0
pod 0 4 0.0
total 67 71 94.3


line stmt bran cond sub pod time code
1             package Path::Tiny::Glob::Visitor;
2             our $AUTHORITY = 'cpan:YANICK';
3             # ABSTRACT: directory visitor for Path::Tiny::Glob
4             $Path::Tiny::Glob::Visitor::VERSION = '0.0.1';
5 1     1   547 use Moo;
  1         11022  
  1         5  
6              
7             require Path::Tiny;
8 1     1   1954 use List::Lazy qw/ lazy_fixed_list /;
  1         67284  
  1         9  
9              
10 1         7 use experimental qw/
11             signatures
12             postderef
13 1     1   372 /;
  1         3  
14              
15             has path => (
16             is => 'ro',
17             required => 1,
18             );
19              
20             has globs => (
21             is => 'ro',
22             required => 1,
23             );
24              
25             has children => (
26             is => 'ro',
27             lazy => 1,
28             default => sub {
29             [ Path::Tiny::path($_[0]->path)->children ];
30             }
31             );
32              
33             has found => (
34             is => 'ro',
35             default => sub { [] },
36             );
37              
38             has next => (
39             is => 'ro',
40             default => sub { +{} },
41             );
42              
43 31     31 0 177 sub as_list($self) {
  31         43  
  31         49  
44              
45 31         75 for my $g ( $self->globs->@* ) {
46 31         65 $self->match( $g );
47             }
48              
49 31         175 return lazy_fixed_list $self->found->@*, $self->subvisitors;
50             }
51              
52 31     31 0 45 sub subvisitors($self) {
  31         47  
  31         40  
53 31         119 my @paths = sort keys $self->next->%*;
54              
55             return map {
56 31         71 Path::Tiny::Glob::Visitor->new(
57             path => $_,
58 26         576 globs => $self->next->{$_},
59             )->as_list
60             } @paths;
61             }
62            
63 36     36 0 52 sub match( $self, $glob ) {
  36         100  
  36         47  
  36         48  
64 36         108 my( $head, $rest ) = split '/', $glob, 2;
65              
66 36 100       97 if( $head eq '.' ) {
67 1         6 return $self->match( $rest );
68             }
69              
70 35 100       71 if( $head eq '**' ) {
71              
72 5 100       13 return unless $rest;
73              
74 4         63 push $self->next->{$_}->@*, "**/$rest" for grep { $_->is_dir } $self->children->@*;
  4         564  
75 4         118 $self->match( split '/', $rest, 2 );
76 4         33 return;
77              
78             }
79              
80             # TODO optimize for when there is no globbing (no need
81             # to check all the children)
82 30 100       59 if( $rest ) {
83 1     1   612 no warnings;
  1         2  
  1         269  
84 23         380 push $self->next->{$_}->@*, $rest for grep {
85 92         570 $_->basename =~ glob2re($head) }
86 207         11733 grep { $_->is_dir } $self->children->@*;
87 23         177 return;
88             }
89             else {
90 7         150 push $self->found->@*, grep { $_->is_file } grep { $_->basename =~ glob2re($head) } $self->children->@*;
  4         13  
  7         427  
91             }
92             }
93              
94 99     99 0 2015 sub glob2re($glob) {
  99         143  
  99         129  
95 99         162 $glob =~ s/\?/.?/g;
96 99         152 $glob =~ s/\*/.*/g;
97 99         926 return qr/^$glob$/;
98             }
99              
100             1;
101              
102             __END__