File Coverage

blib/lib/Module/List.pm
Criterion Covered Total %
statement 56 64 87.5
branch 18 28 64.2
condition 24 33 72.7
subroutine 8 8 100.0
pod 1 1 100.0
total 107 134 79.8


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::",
10             { list_modules => 1});
11             $prefixes = list_modules("",
12             { list_prefixes => 1, recurse => 1 });
13              
14             =head1 DESCRIPTION
15              
16             This module deals with the examination of the namespace of Perl modules.
17             The contents of the module namespace is split across several physical
18             directory trees, but this module hides that detail, providing instead
19             a view of the abstract namespace.
20              
21             =cut
22              
23             package Module::List;
24              
25 1     1   24391 { use 5.006; }
  1         3  
  1         34  
26 1     1   4 use warnings;
  1         2  
  1         22  
27 1     1   4 use strict;
  1         15  
  1         37  
28              
29 1     1   5 use Carp qw(croak);
  1         2  
  1         70  
30 1     1   4 use File::Spec;
  1         2  
  1         18  
31 1     1   752 use IO::Dir 1.03;
  1         37853  
  1         76  
32              
33             our $VERSION = "0.003";
34              
35 1     1   1072 use parent "Exporter";
  1         325  
  1         5  
36             our @EXPORT_OK = qw(list_modules);
37              
38             =head1 FUNCTIONS
39              
40             =over
41              
42             =item list_modules(PREFIX, OPTIONS)
43              
44             This function generates a listing of the contents of part of the module
45             namespace. The part of the namespace under the module name prefix PREFIX
46             is examined, and information about it returned as specified by OPTIONS.
47              
48             Module names are handled by this function in standard bareword syntax.
49             They are always fully-qualified; isolated name components are never used.
50             A module name prefix is the part of a module name that comes before
51             a component of the name, and so either ends with "::" or is the empty
52             string.
53              
54             OPTIONS is a reference to a hash, the elements of which specify what is
55             to be returned. The options are:
56              
57             =over
58              
59             =item list_modules
60              
61             Truth value, default false. If true, return names of modules in the relevant
62             part of the namespace.
63              
64             =item list_prefixes
65              
66             Truth value, default false. If true, return module name prefixes in the
67             relevant part of the namespace. Note that prefixes are returned if the
68             corresponding directory exists, even if there is nothing in it.
69              
70             =item list_pod
71              
72             Truth value, default false. If true, return names of POD documentation
73             files that are in the module namespace.
74              
75             =item trivial_syntax
76              
77             Truth value, default false. If false, only valid bareword names are
78             permitted. If true, bareword syntax is ignored, and any "::"-separated
79             name that can be turned into a correct filename by interpreting name
80             components as filename components is permitted. This is of no use in
81             listing actual Perl modules, because the illegal names can't be used in
82             Perl, but some programs such as B use a "::"-separated name for
83             the sake of appearance without really using bareword syntax. The loosened
84             syntax applies both to the names returned and to the I parameter.
85              
86             Precisely, the `trivial syntax' is that each "::"-separated component
87             cannot be "." or "..", cannot contain "::" or "/", and (except for the
88             final component of a leaf name) cannot end with ":". This is precisely
89             what is required to achieve a unique interconvertible "::"-separated path
90             syntax on Unix. This criterion might change in the future on non-Unix
91             systems, where the filename syntax differs.
92              
93             =item recurse
94              
95             Truth value, default false. If false, only names at the next level down
96             from PREFIX (having one more component) are returned. If true, names
97             at all lower levels are returned.
98              
99             =item use_pod_dir
100              
101             Truth value, default false. If false, POD documentation files are
102             expected to be in the same directory that the corresponding module file
103             would be in. If true, POD files may also be in a subdirectory of that
104             named "C". (Any POD files in such a subdirectory will therefore be
105             visible under two module names, one treating the "C" subdirectory
106             level as part of the module name.)
107              
108             =back
109              
110             Note that the default behaviour, if an empty options hash is supplied, is
111             to return nothing. You I specify what kind of information you want.
112              
113             The function returns a reference to a hash, the keys of which are the
114             names of interest. The value associated with each of these keys is undef.
115              
116             =cut
117              
118             sub list_modules($$) {
119 7     7 1 21474 my($prefix, $options) = @_;
120 7         19 my $trivial_syntax = $options->{trivial_syntax};
121 7         11 my($root_leaf_rx, $root_notleaf_rx);
122 0         0 my($notroot_leaf_rx, $notroot_notleaf_rx);
123 7 50       22 if($trivial_syntax) {
124 0         0 $root_leaf_rx = $notroot_leaf_rx = qr#:?(?:[^/:]+:)*[^/:]+:?#;
125 0         0 $root_notleaf_rx = $notroot_notleaf_rx =
126             qr#:?(?:[^/:]+:)*[^/:]+#;
127             } else {
128 7         34 $root_leaf_rx = $root_notleaf_rx = qr/[a-zA-Z_][0-9a-zA-Z_]*/;
129 7         26 $notroot_leaf_rx = $notroot_notleaf_rx = qr/[0-9a-zA-Z_]+/;
130             }
131 7 50 33     151 croak "bad module name prefix `$prefix'"
132             unless $prefix =~ /\A(?:${root_notleaf_rx}::
133             (?:${notroot_notleaf_rx}::)*)?\z/x &&
134             $prefix !~ /(?:\A|[^:]::)\.\.?::/;
135 7         18 my $list_modules = $options->{list_modules};
136 7         12 my $list_prefixes = $options->{list_prefixes};
137 7         149 my $list_pod = $options->{list_pod};
138 7         13 my $use_pod_dir = $options->{use_pod_dir};
139 7 100 100     51 return {} unless $list_modules || $list_prefixes || $list_pod;
      66        
140 5         8 my $recurse = $options->{recurse};
141 5         12 my @prefixes = ($prefix);
142 5         8 my %seen_prefixes;
143             my %results;
144 5         15 while(@prefixes) {
145 5         10 my $prefix = pop(@prefixes);
146 5         14 my @dir_suffix = split(/::/, $prefix);
147 5 100       12 my $module_rx =
148             $prefix eq "" ? $root_leaf_rx : $notroot_leaf_rx;
149 5         114 my $pm_rx = qr/\A($module_rx)\.pmc?\z/;
150 5         60 my $pod_rx = qr/\A($module_rx)\.pod\z/;
151 5 100       17 my $dir_rx =
152             $prefix eq "" ? $root_notleaf_rx : $notroot_notleaf_rx;
153 5         47 $dir_rx = qr/\A$dir_rx\z/;
154 5         1143 foreach my $incdir (@INC) {
155 55         2019 my $dir = File::Spec->catdir($incdir, @dir_suffix);
156 55 100       337 my $dh = IO::Dir->new($dir) or next;
157 37         2853 while(defined(my $entry = $dh->read)) {
158 936 100 100     38899 if(($list_modules && $entry =~ $pm_rx) ||
    100 33        
      66        
      66        
      100        
      100        
      100        
159             ($list_pod &&
160             $entry =~ $pod_rx)) {
161 213         1131 $results{$prefix.$1} = undef;
162             } elsif(($list_prefixes || $recurse) &&
163             File::Spec
164             ->no_upwards($entry) &&
165             $entry =~ $dir_rx &&
166             -d File::Spec->catdir($dir,
167             $entry)) {
168 304         539 my $newpfx = $prefix.$entry."::";
169 304 50       648 next if exists $seen_prefixes{$newpfx};
170 304 50       893 $results{$newpfx} = undef
171             if $list_prefixes;
172 304 50       1404 push @prefixes, $newpfx if $recurse;
173             }
174             }
175 37 50 33     1332 next unless $list_pod && $use_pod_dir;
176 0         0 $dir = File::Spec->catdir($dir, "pod");
177 0 0       0 $dh = IO::Dir->new($dir) or next;
178 0         0 while(defined(my $entry = $dh->read)) {
179 0 0       0 if($entry =~ $pod_rx) {
180 0         0 $results{$prefix.$1} = undef;
181             }
182             }
183             }
184             }
185 5         192 return \%results;
186             }
187              
188             =back
189              
190             =head1 SEE ALSO
191              
192             L
193              
194             =head1 AUTHOR
195              
196             Andrew Main (Zefram)
197              
198             =head1 COPYRIGHT
199              
200             Copyright (C) 2004, 2006, 2009, 2011
201             Andrew Main (Zefram)
202              
203             =head1 LICENSE
204              
205             This module is free software; you can redistribute it and/or modify it
206             under the same terms as Perl itself.
207              
208             =cut
209              
210             1;