File Coverage

blib/lib/Path/Tiny/Glob/Visitor.pm
Criterion Covered Total %
statement 67 67 100.0
branch 20 22 90.9
condition 2 4 50.0
subroutine 14 14 100.0
pod 0 6 0.0
total 103 113 91.1


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.2.0';
5 3     3   1292 use Moo;
  3         27968  
  3         13  
6              
7             require Path::Tiny;
8 3     3   5224 use List::Lazy qw/ lazy_fixed_list /;
  3         168373  
  3         21  
9              
10 3         18 use experimental qw/
11             signatures
12             postderef
13 3     3   935 /;
  3         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 58     58 0 246 sub as_list($self) {
  58         79  
  58         73  
36 58         114 $self->match;
37 58         163 return lazy_fixed_list $self->found->@*, $self->subvisitors;
38             }
39              
40 58     58 0 73 sub subvisitors($self) {
  58         67  
  58         60  
41             return map {
42 58         233 Path::Tiny::Glob::Visitor->new(
43             path => Path::Tiny::path($_),
44 49         119 globs => $self->next->{$_},
45             )->as_list
46             } sort keys $self->next->%*;
47             }
48              
49 58     58 0 68 sub match( $self ) {
  58         69  
  58         59  
50              
51 58         110 my @rules = map { $self->glob2rule( $_ ) } $self->globs->@*;
  58         118  
52              
53             my $state = $self->path->visit(sub {
54 386     386   29264 my( $path, $state ) = @_;
55              
56 386         593 for my $rule ( @rules ) {
57 411 100       828 next unless $rule->[0]->($path);
58 62 100       1514 if( $rule->[1] ) {
59 49   50     154 $state->{path}{$path}||=[];
60 49         337 push( $state->{path}{$path}->@*, $rule->[1] );
61             }
62             else {
63 13   50     72 $state->{found} ||= [];
64              
65 13         39 push $state->{found}->@*, $path;
66             }
67             }
68 58         258 });
69              
70              
71 58         2947 delete $state->{path}{$_} for keys $state->{found}->@*;
72              
73             $self->next(
74             $state->{path}
75 58 50       240 ) if $state->{path};
76              
77 58         267 $self->found($state->{found});
78             }
79              
80             # turn a glob into a regular expression
81 42     42 0 47 sub glob2re($glob) {
  42         48  
  42         43  
82 42         63 $glob =~ s/\?/.?/g;
83 42         66 $glob =~ s/\*/.*/g;
84 42         505 return qr/^$glob$/;
85             }
86              
87 67     67 0 83 sub glob2rule($self,$glob) {
  67         70  
  67         70  
  67         69  
88 67         148 my( $head, @rest ) = @$glob;
89              
90 67 100       133 if ( $head eq '.' ) {
91 1         5 return $self->glob2rule(\@rest);
92             }
93              
94 66 100       112 if( $head eq '**' ) {
95 20 100   10   64 return [ sub { $_[0]->is_dir }, $glob ], $self->glob2rule(\@rest) if @rest;
  10         22  
96              
97 12     15   77 return [ sub { $_[0]->is_file } ], [ sub { $_[0]->is_dir }, ['**'] ];
  15         40  
  15         47  
98             }
99              
100 46 100       103 return [ $self->segment2code($head, 'is_dir' ), \@rest ] if @rest;
101              
102 12         28 return [ $self->segment2code($head, ('is_file') x ! ref $head) ];
103              
104             }
105              
106 46     46 0 73 sub segment2code($self,$segment,$type_test=undef) {
  46         56  
  46         58  
  46         63  
  46         49  
107              
108 46 100       98 $segment = glob2re($segment) unless ref $segment;
109              
110             my $test = ref $segment eq 'Regexp'
111 143     143   2675 ? sub { $_->basename =~ $segment }
112 46 50       217 : $segment;
113              
114 46 100   366   302 return $type_test ? sub { $_->$type_test and $test->() } : $test;
  366 100       730  
115             }
116              
117              
118              
119             1;
120              
121             __END__