File Coverage

blib/lib/Path/List/Rule.pm
Criterion Covered Total %
statement 78 88 88.6
branch 23 28 82.1
condition n/a
subroutine 17 23 73.9
pod 1 1 100.0
total 119 140 85.0


line stmt bran cond sub pod time code
1             package Path::List::Rule;
2              
3             # ABSTRACT: Path::Iterator::Rule on an list of paths
4              
5 1     1   222685 use 5.012;
  1         9  
6              
7 1     1   5 use strict;
  1         2  
  1         19  
8 1     1   4 use warnings;
  1         2  
  1         38  
9              
10             our $VERSION = '0.02';
11              
12 1     1   480 use File::Spec::Functions ();
  1         852  
  1         27  
13 1     1   414 use parent 'Path::Iterator::Rule';
  1         277  
  1         5  
14              
15             {
16             package # avoid CPAN indexing
17             Path::List::Rule::Entry;
18              
19             use overload
20             '-X' => '_statit',
21 45     45   1158 'bool' => sub { 1 },
22 1         10 '""' => 'stringify',
23             fallback => 1,
24 1     1   15139 ;
  1         2  
25              
26             sub _croak {
27 0     0   0 require Carp;
28 0         0 goto \&Carp::croak;
29             }
30              
31             sub new {
32 45     45   90 my ( $class, $fs, $path, $leaf ) = @_;
33              
34 45 100       108 substr($path,-1,1,'') if substr($path,-1,1) eq q{/};
35 45         144 my %self = (
36             exists => 1,
37             path => $path,
38             leaf => $leaf,
39             fs => {},
40             );
41              
42             # doesn't exist
43 45 50       106 if ( !defined $fs ) {
    100          
44 0         0 $self{is_dir} = $self{is_file} = $self{exists} = 0;
45             }
46             # maybe a file
47             elsif ( defined $leaf ) {
48 44         78 $self{is_dir} = defined $fs->{$leaf};
49 44         75 $self{is_file} = !defined $fs->{$leaf};
50 44 100       102 $self{fs} = $fs->{$leaf} if $self{is_dir};
51             }
52             # not a file
53             else {
54 1         3 $self{is_dir} = 1;
55 1         2 $self{is_file} = 0;
56 1         2 $self{fs} = $fs;
57             }
58              
59 45         137 return bless \%self, $class;
60             }
61              
62             sub _children {
63 30     30   41 my $self = shift;
64 30         41 return map { __PACKAGE__->new( $self->{fs}, "$self->{path}/$_", $_ ) } keys %{ $self->{fs} };
  40         123  
  30         95  
65             }
66              
67             sub _statit {
68 156     156   4869 my ( $self, $op ) = @_;
69 156 50       293 if ( $op eq 'e' ) { return $self->{exists} }
  0         0  
70 156 100       285 if ( $op eq 'l' ) { return 0; }
  45         97  
71 111 100       218 if ( $op eq 'r' ) { return 1; }
  30 100       60  
    50          
72 54         135 elsif ( $op eq 'd' ) { return $self->{is_dir} }
73 27         80 elsif ( $op eq 'f' ) { return $self->{is_file} }
74 0         0 else { _croak( "unsupported file test: -$op\n" ) }
75             }
76              
77             sub is_dir {
78 0     0   0 return !! $_[0]->{is_dir};
79             }
80              
81             sub is_file {
82 0     0   0 return !! $_[0]->{is_file};
83             }
84              
85             sub exists {
86 0     0   0 return !! $_[0]->{exists};
87             }
88              
89             sub stringify {
90 24     24   183 return $_[0]->{path};
91             }
92              
93             }
94              
95             sub _deconstruct_path {
96 9     9   13 my $path = shift;
97 9         24 my ( $volume, $directories, $file ) = File::Spec::Functions::splitpath( $path );
98 9         120 my @dirs = File::Spec::Functions::splitdir( $directories );
99 9 50       54 pop @dirs if !length( $dirs[-1] );
100 9 100       24 $file = undef if !length( $file );
101 9         30 return ( $volume, $file, @dirs );
102             }
103              
104             sub new {
105 1     1 1 100 my $class = shift;
106 1         2 my $paths = shift;
107 1         2 my %fs;
108              
109             # let's create our "filesystem"! leafs which we know are
110             # directories are set to an empty hash; otherwise undef.
111 1         3 for my $path ( @{$paths} ) {
  1         3  
112 4         10 my ( $volume, $file, @dirs ) = _deconstruct_path( $path );
113 4         7 my $ref = \%fs;
114 4         9 for my $entry ( $volume, @dirs ) {
115 15 100       45 $ref->{$entry} = {} if !exists $ref->{$entry};
116 15         22 $ref = $ref->{$entry};
117             }
118 4 100       21 $ref->{$file} = undef if defined $file;
119             }
120              
121 1         13 my $self = $class->SUPER::new();
122 1         14 $self->{_fs} = \%fs;
123              
124 1         4 return $self;
125             }
126              
127             sub _objectify {
128 5     5   171 my ( $self, $path ) = @_;
129              
130 5         11 my ( $volume, $file, @dirs ) = _deconstruct_path( $path );
131 5         12 my $ref = $self->{_fs};
132 5         6 my $exists = 1;
133 5         12 for my $entry ( $volume, @dirs ) {
134             $exists = 0, last
135 6 50       15 if !exists $ref->{$entry};
136 6         13 $ref = $ref->{$entry};
137             }
138 5         22 return Path::List::Rule::Entry->new( $ref, $path, $file );
139             }
140              
141             sub _children {
142 30     30   632 my ( $self, $path ) = @_;
143 30         64 return map { [ $_->{leaf}, $_ ] } $path->_children;
  40         124  
144             }
145              
146             sub _defaults {
147             return (
148             _stringify => 0,
149             follow_symlinks => 1,
150             depthfirst => 0,
151             sorted => 1,
152             loop_safe => 1,
153 0     0   0 error_handler => sub { die sprintf( "%s: %s", @_ ) },
154 5     5   15653 visitor => undef,
155             );
156             }
157              
158             sub _fast_defaults {
159              
160             return (
161 0     0   0 _stringify => 0,
162             follow_symlinks => 1,
163             depthfirst => -1,
164             sorted => 0,
165             loop_safe => 0,
166             error_handler => undef,
167             visitor => undef,
168             );
169             }
170              
171             sub _iter {
172 5     5   10 my $self = shift;
173 5         7 my $defaults = shift;
174 5         10 $defaults->{loop_safe} = 0;
175 5         17 $self->SUPER::_iter( $defaults, @_ );
176             }
177              
178             1;
179              
180             #
181             # This file is part of Path-List-Rule
182             #
183             # This software is copyright (c) 2022 by Smithsonian Astrophysical Observatory.
184             #
185             # This is free software; you can redistribute it and/or modify it under
186             # the same terms as the Perl 5 programming language system itself.
187             #
188              
189             __END__