File Coverage

blib/lib/Path/Tiny/Glob/Visitor.pm
Criterion Covered Total %
statement 66 66 100.0
branch 20 22 90.9
condition 1 2 50.0
subroutine 14 14 100.0
pod 0 6 0.0
total 101 110 91.8


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.1.0';
5 2     2   1144 use Moo;
  2         23091  
  2         10  
6              
7             require Path::Tiny;
8 2     2   4026 use List::Lazy qw/ lazy_fixed_list /;
  2         137212  
  2         19  
9              
10 2         19 use experimental qw/
11             signatures
12             postderef
13 2     2   855 /;
  2         5  
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 found => (
26             is => 'rw',
27             default => sub { [] },
28             );
29              
30             has next => (
31             is => 'rw',
32             default => sub { +{} },
33             );
34              
35 40     40 0 209 sub as_list($self) {
  40         75  
  40         48  
36 40         102 $self->match;
37 40         137 return lazy_fixed_list $self->found->@*, $self->subvisitors;
38             }
39              
40 40     40 0 57 sub subvisitors($self) {
  40         56  
  40         60  
41             return map {
42 40         155 Path::Tiny::Glob::Visitor->new(
43             path => Path::Tiny::path($_),
44 34         104 globs => $self->next->{$_},
45             )->as_list
46             } sort keys $self->next->%*;
47             }
48              
49 40     40 0 55 sub match( $self ) {
  40         52  
  40         50  
50              
51 40         100 my @rules = map { $self->glob2rule( $_ ) } $self->globs->@*;
  40         80  
52              
53             my $state = $self->path->visit(sub {
54 275     275   25838 my( $path, $state ) = @_;
55              
56 275         529 for my $rule ( @rules ) {
57 290 100       700 next unless $rule->[0]->($path);
58 42 100       1330 if( $rule->[1] ) {
59 34   50     132 $state->{path}{$path}||=[];
60 34         304 push( $state->{path}{$path}->@*, $rule->[1] );
61             }
62             else {
63 8         33 $state->{found}{$path} = 1;
64             }
65             }
66 40         218 });
67              
68              
69 40         2542 delete $state->{path}{$_} for keys $state->{found}->%*;
70              
71             $self->next(
72             $state->{path}
73 40 50       195 ) if $state->{path};
74              
75 40         298 $self->found([ keys $state->{found}->%* ]);
76             }
77              
78             # turn a glob into a regular expression
79 32     32 0 41 sub glob2re($glob) {
  32         66  
  32         42  
80 32         59 $glob =~ s/\?/.?/g;
81 32         56 $glob =~ s/\*/.*/g;
82 32         437 return qr/^$glob$/;
83             }
84              
85 49     49 0 63 sub glob2rule($self,$glob) {
  49         62  
  49         73  
  49         56  
86 49         129 my( $head, @rest ) = @$glob;
87              
88 49 100       116 if ( $head eq '.' ) {
89 1         6 return $self->glob2rule(\@rest);
90             }
91              
92 48 100       90 if( $head eq '**' ) {
93 12 100   10   53 return [ sub { $_[0]->is_dir }, $glob ], $self->glob2rule(\@rest) if @rest;
  10         29  
94              
95 4     5   31 return [ sub { $_[0]->is_file } ], [ sub { $_[0]->is_dir }, ['**'] ];
  5         15  
  5         18  
96             }
97              
98 36 100       94 return [ $self->segment2code($head, 'is_dir' ), \@rest ] if @rest;
99              
100 11         27 return [ $self->segment2code($head, ('is_file') x ! ref $head) ];
101              
102             }
103              
104 36     36 0 55 sub segment2code($self,$segment,$type_test=undef) {
  36         49  
  36         56  
  36         51  
  36         45  
105              
106 36 100       95 $segment = glob2re($segment) unless ref $segment;
107              
108             my $test = ref $segment eq 'Regexp'
109 121     121   2681 ? sub { $_->basename =~ $segment }
110 36 50       192 : $segment;
111              
112 36 100   265   219 return $type_test ? sub { $_->$type_test and $test->() } : $test;
  265 100       681  
113             }
114              
115              
116              
117             1;
118              
119             __END__