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