File Coverage

blib/lib/Module/List.pm
Criterion Covered Total %
statement 74 95 77.8
branch 27 42 64.2
condition 18 27 66.6
subroutine 8 8 100.0
pod 1 1 100.0
total 128 173 73.9


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Module::List - module `directory' listing
4              
5             =head1 SYNOPSIS
6              
7             use Module::List qw(list_modules);
8              
9             $id_modules = list_modules("Data::ID::", { list_modules => 1});
10             $prefixes = list_modules("",
11             { list_prefixes => 1, recurse => 1 });
12              
13             =head1 DESCRIPTION
14              
15             This module deals with the examination of the namespace of Perl modules.
16             The contents of the module namespace is split across several physical
17             directory trees, but this module hides that detail, providing instead
18             a view of the abstract namespace.
19              
20             =cut
21              
22             package Module::List;
23              
24 2     2   519746 { use 5.006; }
  2         8  
25 2     2   21 use warnings;
  2         5  
  2         166  
26 2     2   20 use strict;
  2         6  
  2         86  
27              
28 2     2   28 use Carp qw(croak);
  2         5  
  2         141  
29 2     2   16 use File::Spec;
  2         4  
  2         95  
30 2     2   1207 use IO::Dir 1.03;
  2         56234  
  2         162  
31              
32             our $VERSION = "0.004";
33              
34 2     2   529 use parent "Exporter";
  2         388  
  2         48  
35             our @EXPORT_OK = qw(list_modules);
36              
37             =head1 FUNCTIONS
38              
39             =over
40              
41             =item list_modules(PREFIX, OPTIONS)
42              
43             This function generates a listing of the contents of part of the module
44             namespace. The part of the namespace under the module name prefix PREFIX
45             is examined, and information about it returned as specified by OPTIONS.
46              
47             Module names are handled by this function in standard bareword syntax.
48             They are always fully-qualified; isolated name components are never used.
49             A module name prefix is the part of a module name that comes before
50             a component of the name, and so either ends with "::" or is the empty
51             string.
52              
53             OPTIONS is a reference to a hash, the elements of which specify what is
54             to be returned. The options are:
55              
56             =over
57              
58             =item list_modules
59              
60             Truth value, default false. If true, return names of modules in the relevant
61             part of the namespace.
62              
63             =item list_prefixes
64              
65             Truth value, default false. If true, return module name prefixes in the
66             relevant part of the namespace. Note that prefixes are returned if the
67             corresponding directory exists, even if there is nothing in it.
68              
69             =item list_pod
70              
71             Truth value, default false. If true, return names of POD documentation
72             files that are in the module namespace.
73              
74             =item trivial_syntax
75              
76             Truth value, default false. If false, only valid bareword names are
77             permitted. If true, bareword syntax is ignored, and any "::"-separated
78             name that can be turned into a correct filename by interpreting name
79             components as filename components is permitted. This is of no use in
80             listing actual Perl modules, because the illegal names can't be used in
81             Perl, but some programs such as B use a "::"-separated name for
82             the sake of appearance without really using bareword syntax. The loosened
83             syntax applies both to the names returned and to the I parameter.
84              
85             Precisely, the `trivial syntax' is that each "::"-separated component
86             cannot be "." or "..", cannot contain "::" or "/", and (except for the
87             final component of a leaf name) cannot end with ":". This is precisely
88             what is required to achieve a unique interconvertible "::"-separated path
89             syntax on Unix. This criterion might change in the future on non-Unix
90             systems, where the filename syntax differs.
91              
92             =item recurse
93              
94             Truth value, default false. If false, only names at the next level down
95             from PREFIX (having one more component) are returned. If true, names
96             at all lower levels are returned.
97              
98             =item use_pod_dir
99              
100             Truth value, default false. If false, POD documentation files are
101             expected to be in the same directory that the corresponding module file
102             would be in. If true, POD files may also be in a subdirectory of that
103             named "C". (Any POD files in such a subdirectory will therefore be
104             visible under two module names, one treating the "C" subdirectory
105             level as part of the module name.)
106              
107             =item return_path
108              
109             Truth value, default false. If false, only the existence of requested
110             items is reported. If true, the pathnames of the files in which they
111             exist are reported.
112              
113             =back
114              
115             Note that the default behaviour, if an empty options hash is supplied, is
116             to return nothing. You I specify what kind of information you want.
117              
118             The function returns a reference to a hash, the keys of which are the
119             names of interest. By default, the value associated with each of these
120             keys is undef. If additional information about each item was requested,
121             the value for each item is a reference to a hash, containing some subset
122             of these items:
123              
124             =over
125              
126             =item module_path
127              
128             Pathname of the module of this name. Specifically, this identifies
129             the file that would be read in order to load the module. This may be
130             a C<.pmc> file if one is available. Absent if there is no module.
131              
132             =item pod_path
133              
134             Pathname of the POD document of this name. Absent if there is no
135             discrete POD document. (POD in a module file doesn't constitute a
136             discrete POD document.)
137              
138             =item prefix_paths
139              
140             Reference to an array of the pathnames of the directories referenced
141             by this prefix. The directories are listed in the order corresponding
142             to @INC. Absent if this is not a prefix.
143              
144             =back
145              
146             =cut
147              
148             sub list_modules($$) {
149 8     8 1 286976 my($prefix, $options) = @_;
150 8         24 my $trivial_syntax = $options->{trivial_syntax};
151 8         25 my($root_leaf_rx, $root_notleaf_rx);
152 8         0 my($notroot_leaf_rx, $notroot_notleaf_rx);
153 8 50       27 if($trivial_syntax) {
154 0         0 $root_leaf_rx = $notroot_leaf_rx = qr#:?(?:[^/:]+:)*[^/:]+:?#;
155 0         0 $root_notleaf_rx = $notroot_notleaf_rx = qr#:?(?:[^/:]+:)*[^/:]+#;
156             } else {
157 8         56 $root_leaf_rx = $root_notleaf_rx = qr/[a-zA-Z_][0-9a-zA-Z_]*/;
158 8         28 $notroot_leaf_rx = $notroot_notleaf_rx = qr/[0-9a-zA-Z_]+/;
159             }
160 8 50 33     218 croak "bad module name prefix `$prefix'"
161             unless $prefix =~ /\A(?:${root_notleaf_rx}::
162             (?:${notroot_notleaf_rx}::)*)?\z/x &&
163             $prefix !~ /(?:\A|[^:]::)\.\.?::/;
164 8         23 my $list_modules = $options->{list_modules};
165 8         15 my $list_prefixes = $options->{list_prefixes};
166 8         15 my $list_pod = $options->{list_pod};
167 8         20 my $use_pod_dir = $options->{use_pod_dir};
168 8 100 100     47 return {} unless $list_modules || $list_prefixes || $list_pod;
      66        
169 6         11 my $recurse = $options->{recurse};
170 6         13 my $return_path = $options->{return_path};
171 6         20 my @prefixes = ($prefix);
172 6         13 my %seen_prefixes;
173             my %results;
174 6         66 while(@prefixes) {
175 6         16 my $prefix = pop(@prefixes);
176 6         94 my @dir_suffix = split(/::/, $prefix);
177 6 100       25 my $module_rx = $prefix eq "" ? $root_leaf_rx : $notroot_leaf_rx;
178 6         121 my $pmc_rx = qr/\A($module_rx)\.pmc\z/;
179 6         77 my $pm_rx = qr/\A($module_rx)\.pm\z/;
180 6         118 my $pod_rx = qr/\A($module_rx)\.pod\z/;
181 6 100       18 my $dir_rx = $prefix eq "" ? $root_notleaf_rx : $notroot_notleaf_rx;
182 6         68 $dir_rx = qr/\A$dir_rx\z/;
183 6         19 foreach my $incdir (@INC) {
184 48         2489 my $dir = File::Spec->catdir($incdir, @dir_suffix);
185 48 100       247 my $dh = IO::Dir->new($dir) or next;
186 32         3379 my @entries = $dh->read;
187 32         4019 $dh->close;
188 32 100       749 if($list_modules) {
189 24         65 foreach my $pmish_rx ($pmc_rx, $pm_rx) {
190 48         91 foreach my $entry (@entries) {
191 1404 100       5200 if($entry =~ $pmish_rx) {
192 240         655 my $name = $prefix.$1;
193 240 100       479 if($return_path) {
194 12         111 my $path = File::Spec->catfile($dir, $entry);
195 12   100     71 $results{$name} ||= {};
196             $results{$name}->{module_path} = $path
197             unless
198 12 100       44 exists($results{$name}->{module_path});
199             } else {
200 228         675 $results{$name} = undef;
201             }
202             }
203             }
204             }
205             }
206 32 50       76 if($list_pod) {
207 0         0 my @poddirs = [ $dir, \@entries ];
208 0 0       0 if($use_pod_dir) {
209 0         0 my $pdir = File::Spec->catdir($dir, "pod");
210 0         0 my $pdh = IO::Dir->new($pdir);
211 0 0       0 if($pdh) {
212 0         0 push @poddirs, [ $pdir, [$pdh->read] ];
213 0         0 $pdh->close;
214             }
215             }
216 0         0 foreach(@poddirs) {
217 0         0 my($dir, $entries) = @$_;
218 0         0 foreach my $entry (@$entries) {
219 0 0       0 if($entry =~ $pod_rx) {
220 0         0 my $name = $prefix.$1;
221 0 0       0 if($return_path) {
222 0         0 my $path = File::Spec->catfile($dir, $entry);
223 0   0     0 $results{$name} ||= {};
224             $results{$name}->{pod_path} = $path
225 0 0       0 unless exists($results{$name}->{pod_path});
226             } else {
227 0         0 $results{$name} = undef;
228             }
229             }
230             }
231             }
232             }
233 32 100 66     183 if($list_prefixes || $recurse) {
234 24         46 foreach my $entry (@entries) {
235 702 100 100     24721 if(File::Spec->no_upwards($entry) && $entry =~ $dir_rx &&
      100        
236             -d File::Spec->catdir($dir, $entry)) {
237 352         1049 my $newpfx = $prefix.$entry."::";
238 352 50 33     768 if($recurse && !exists($seen_prefixes{$newpfx})) {
239 0         0 push @prefixes, $newpfx;
240 0         0 $seen_prefixes{$newpfx} = undef;
241             }
242 352 50       675 if($list_prefixes) {
243 352 100       631 if($return_path) {
244 3   50     42 $results{$newpfx} ||= { prefix_paths => [] };
245 3         4 push @{$results{$newpfx}->{prefix_paths}},
  3         37  
246             File::Spec->catfile($dir, $entry);
247             } else {
248 349         1676 $results{$newpfx} = undef;
249             }
250             }
251             }
252             }
253             }
254             }
255             }
256 6         555 return \%results;
257             }
258              
259             =back
260              
261             =head1 SEE ALSO
262              
263             L will list all modules available, but taking
264             a partial path rather than a module name.
265              
266             L gives you quite a bit of control but as a result
267             has a more complex interface.
268              
269             L looks for modules, and seems to be aimed at
270             finding plugins in a namespace.
271              
272             L can look for, and load, modules in a given namespace,
273             for example looking for plugins or drivers.
274              
275             There are also a number of modules which will take a module name
276             and tell you where that is installed locally,
277             such as L, L, L,
278             and others.
279              
280             L can find modules that start with a specified substring,
281             such as C, and then can also be used to load them.
282             It was inspired by L.
283              
284             L gives your module the ability to have plugins,
285             finding plugin modules which match a pattern.
286              
287             L is another module that can be used to find
288             plugin modules.
289              
290             PERLANCAR has released multiple modules based on C:
291             L, L, L,
292             L, and others.
293              
294             L
295              
296             =head1 AUTHOR
297              
298             Andrew Main (Zefram).
299              
300             Now being maintained by Neil Bowers.
301              
302             =head1 COPYRIGHT
303              
304             Copyright (C) 2004, 2006, 2009, 2011, 2017
305             Andrew Main (Zefram)
306              
307             =head1 LICENSE
308              
309             This module is free software; you can redistribute it and/or modify it
310             under the same terms as Perl itself.
311              
312             =cut
313              
314             1;