File Coverage

blib/lib/Module/Path/More.pm
Criterion Covered Total %
statement 56 63 88.8
branch 26 42 61.9
condition 15 24 62.5
subroutine 6 7 85.7
pod 2 2 100.0
total 105 138 76.0


line stmt bran cond sub pod time code
1             package Module::Path::More;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2021-07-20'; # DATE
5             our $DIST = 'Module-Path-More'; # DIST
6             our $VERSION = '0.340'; # VERSION
7              
8 1     1   24032 use 5.010001;
  1         11  
9 1     1   4 use strict;
  1         1  
  1         20  
10 1     1   4 use warnings;
  1         2  
  1         180  
11              
12             require Exporter;
13             our @ISA = qw(Exporter);
14             our @EXPORT_OK = qw(module_path pod_path);
15              
16             our $SEPARATOR;
17              
18             our %SPEC;
19              
20             $SPEC{':package'} = {
21             v => 1.1,
22             summary => 'Get path to locally installed Perl module',
23             };
24              
25             BEGIN {
26 1 50   1   17 if ($^O =~ /^(dos|os2)/i) {
    50          
27 0         0 $SEPARATOR = '\\';
28             } elsif ($^O =~ /^MacOS/i) {
29 0         0 $SEPARATOR = ':';
30             } else {
31 1         774 $SEPARATOR = '/';
32             }
33             }
34              
35             $SPEC{module_path} = {
36             v => 1.1,
37             summary => 'Get path to locally installed Perl module',
38             description => <<'_',
39              
40             Search `@INC` (reference entries are skipped) and return path(s) to Perl module
41             files with the requested name.
42              
43             This function is like the one from , except with a different
44             interface and more options (finding all matches instead of the first, the option
45             of not absolutizing paths, finding `.pmc` & `.pod` files, finding module
46             prefixes).
47              
48             _
49             args => {
50             module => {
51             summary => 'Module name to search',
52             schema => 'str*',
53             req => 1,
54             pos => 0,
55             },
56             find_pm => {
57             summary => 'Whether to find .pm files',
58             schema => ['int*', min=>0],
59             default => 1,
60             description => <<'_',
61              
62             The value of this option is an integer number from 0. 0 means to not search for
63             .pm files, while number larger than 0 means to search for .pm files. The larger
64             the number, the lower the priority. If more than one type is found (prefix, .pm,
65             .pmc, .pod) then the type with the lowest number is returned first.
66              
67             _
68             },
69             find_pmc => {
70             summary => 'Whether to find .pmc files',
71             schema => ['int*', min=>0],
72             default => 2,
73             description => <<'_',
74              
75             The value of this option is an integer number from 0. 0 means to not search for
76             .pmc files, while number larger than 0 means to search for .pmc files. The
77             larger the number, the lower the priority. If more than one type is found
78             (prefix, .pm, .pmc, .pod) then the type with the lowest number is returned
79             first.
80              
81             _
82             },
83             find_pod => {
84             summary => 'Whether to find .pod files',
85             schema => ['int*', min=>0],
86             default => 0,
87             description => <<'_',
88              
89             The value of this option is an integer number from 0. 0 means to not search for
90             .pod files, while number larger than 0 means to search for .pod files. The
91             larger the number, the lower the priority. If more than one type is found
92             (prefix, .pm, .pmc, .pod) then the type with the lowest number is returned
93             first.
94              
95             _
96             },
97             find_prefix => {
98             summary => 'Whether to find module prefixes',
99             schema => ['int*', min=>0],
100             default => 0,
101             description => <<'_',
102              
103             The value of this option is an integer number from 0. 0 means to not search for
104             module prefix, while number larger than 0 means to search for module prefix. The
105             larger the number, the lower the priority. If more than one type is found
106             (prefix, .pm, .pmc, .pod) then the type with the lowest number is returned
107             first.
108              
109             _
110             },
111             all => {
112             summary => 'Return all results instead of just the first',
113             schema => 'bool',
114             default => 0,
115             },
116             abs => {
117             summary => 'Whether to return absolute paths',
118             schema => 'bool',
119             default => 0,
120             },
121             },
122             result => {
123             schema => ['any' => of => ['str*', ['array*' => of => 'str*']]],
124             },
125             result_naked => 1,
126             examples => [
127             {
128             summary => 'Find the first Foo::Bar (.pm or .pmc) in @INC',
129             args => {module => 'Foo::Bar'},
130             },
131             {
132             summary => 'Find all Foo::Bar (.pm or .pmc) in @INC, return absolute paths',
133             args => {module => 'Foo::Bar', all => 1, abs => 1},
134             },
135             {
136             summary => 'Find the Rinci (.pod first, then .pm) in @INC',
137             args => {module => 'Rinci', find_pod => 1, find_pm => 2, find_pmc => 0},
138             },
139             ],
140             };
141             sub module_path {
142 13     13 1 4750 my %args = @_;
143              
144 13 50       36 my $module = $args{module} or die "Please specify module";
145              
146 13   50     67 $args{abs} //= 0;
147 13   50     49 $args{all} //= 0;
148 13   100     37 $args{find_pm} //= 1;
149 13   100     39 $args{find_pmc} //= 2;
150 13   100     37 $args{find_pod} //= 0;
151 13   100     36 $args{find_prefix} //= 0;
152              
153 13 50       24 require Cwd if $args{abs};
154              
155 13         16 my @res;
156             my %unfound = (
157             ("pm" => 1) x !!$args{find_pm},
158             ("pmc" => 1) x !!$args{find_pmc},
159             ("pod" => 1) x !!$args{find_pod},
160             ("prefix" => 1) x !!$args{find_prefix},
161 13         60 );
162             my $add = sub {
163 23     23   49 my ($path, $prio) = @_;
164 23 50       70 push @res, [$args{abs} ? Cwd::abs_path($path) : $path, $prio];
165 13         90 };
166              
167 13         20 my $relpath;
168              
169 13         50 ($relpath = $module) =~ s/::/$SEPARATOR/g;
170 13         32 $relpath =~ s/\.(pm|pmc|pod)\z//i;
171              
172 13         30 foreach my $dir (@INC) {
173 142 50       221 next if not defined($dir);
174 142 50       219 next if ref($dir);
175              
176 142         251 my $prefix = $dir . $SEPARATOR . $relpath;
177 142 50       214 if ($args{find_pm}) {
178 142         200 my $file = $prefix . ".pm";
179 142 100       1613 if (-f $file) {
180 15         49 $add->($file, $args{find_pm});
181 15         30 delete $unfound{pm};
182 15 0 33     33 last if !keys(%unfound) && !$args{all};
183             }
184             }
185 142 100       297 if ($args{find_pmc}) {
186 114         200 my $file = $prefix . ".pmc";
187 114 50       992 if (-f $file) {
188 0         0 $add->($file, $args{find_pmc});
189 0         0 delete $unfound{pmc};
190 0 0 0     0 last if !keys(%unfound) && !$args{all};
191             }
192             }
193 142 100       289 if ($args{find_pod}) {
194 28         51 my $file = $prefix . ".pod";
195 28 100       315 if (-f $file) {
196 3         10 $add->($file, $args{find_pod});
197 3         7 delete $unfound{pod};
198 3 50 66     14 last if !keys(%unfound) && !$args{all};
199             }
200             }
201 140 100       267 if ($args{find_prefix}) {
202 21 100       293 if (-d $prefix) {
203 5         18 $add->($prefix, $args{find_prefix});
204 5         9 delete $unfound{prefix};
205 5 50 66     19 last if !keys(%unfound) && !$args{all};
206             }
207             }
208             }
209              
210 13         52 @res = map { $_->[0] } sort { $a->[1] <=> $b->[1] } @res;
  23         63  
  14         32  
211              
212 13 50       26 if ($args{all}) {
213 0         0 return \@res;
214             } else {
215 13 100       140 return @res ? $res[0] : undef;
216             }
217             }
218              
219             $SPEC{pod_path} = {
220             v => 1.1,
221             summary => 'Get path to locally installed POD',
222             description => <<'_',
223              
224             This is a shortcut for:
225              
226             module_path(%args, find_pm=>0, find_pmc=>0, find_pod=>1, find_prefix=>0)
227              
228             _
229             args => {
230             module => {
231             summary => 'Module name to search',
232             schema => 'str*',
233             req => 1,
234             pos => 0,
235             },
236             all => {
237             summary => 'Return all results instead of just the first',
238             schema => 'bool',
239             default => 0,
240             },
241             abs => {
242             summary => 'Whether to return absolute paths',
243             schema => 'bool',
244             default => 0,
245             },
246             },
247             result => {
248             schema => ['any' => of => ['str*', ['array*' => of => 'str*']]],
249             },
250             result_naked => 1,
251             };
252             sub pod_path {
253 0     0 1   module_path(@_, find_pm=>0, find_pmc=>0, find_pod=>1, find_prefix=>0);
254             }
255              
256             1;
257             # ABSTRACT: Get path to locally installed Perl module
258              
259             __END__