File Coverage

blib/lib/Module/Locate.pm
Criterion Covered Total %
statement 69 82 84.1
branch 27 44 61.3
condition 6 11 54.5
subroutine 16 17 94.1
pod 6 7 85.7
total 124 161 77.0


line stmt bran cond sub pod time code
1             {
2             package Module::Locate;
3             $Module::Locate::VERSION = '1.80';
4 5     5   44567 use warnings;
  5         10  
  5         148  
5 5     5   66 use 5.8.8;
  5         17  
6              
7             our $Cache = 0;
8             our $Global = 1;
9              
10             my $ident_re = qr{[_a-z]\w*}i;
11             my $sep_re = qr{'|::};
12             our $PkgRe = qr{\A(?:$ident_re(?:$sep_re$ident_re)*)\z};
13              
14             my @All = qw(
15             locate get_source acts_like_fh
16             mod_to_path is_mod_loaded is_pkg_loaded
17             );
18              
19             sub import {
20 6     6   978 my $pkg = caller;
21 6         26 my @args = @_[ 1 .. $#_ ];
22            
23 6         1786 while(local $_ = shift @args) {
24 7 100 50     32 *{ "$pkg\::$_" } = \&$_ and next
  6         1802  
25             if defined &$_;
26              
27 1 50       12 $Cache = shift @args, next
28             if /^cache$/i;
29              
30 0 0       0 $Global = shift @args, next
31             if /^global$/i;
32              
33 0 0       0 if(/^:all$/i) {
34 0         0 *{ "$pkg\::$_" } = \&$_
35 0         0 for @All;
36 0         0 next;
37             }
38              
39 0         0 warn("not in ".__PACKAGE__." import list: '$_'");
40             }
41             }
42              
43 5     5   35 use strict;
  5         7  
  5         125  
44              
45 5     5   3156 use IO::File;
  5         40395  
  5         789  
46 5     5   4754 use overload ();
  5         3441  
  5         112  
47 5     5   31 use Carp 'croak';
  5         11  
  5         245  
48 5     5   3930 use File::Spec::Functions 'catfile';
  5         4050  
  5         2946  
49            
50             sub get_source {
51 0     0 1 0 my $pkg = $_[-1];
52              
53 0         0 my $f = locate($pkg);
54              
55             my $fh = ( acts_like_fh($f) ?
56             $f
57             :
58 0 0       0 do { my $tmp = IO::File->new($f)
  0 0       0  
59 0         0 or croak("invalid module '$pkg' [$f] - $!"); $tmp }
60             );
61              
62 0         0 local $/;
63 0         0 return <$fh>;
64             }
65            
66             sub locate {
67 13     13 1 4780 my $pkg = $_[-1];
68              
69 13 50       30 croak("Undefined filename provided")
70             unless defined $pkg;
71            
72 13         25 my $inc_path = mod_to_path($pkg);
73              
74 13 50 33     44 return $INC{$inc_path} if exists($INC{$inc_path}) && !wantarray;
75              
76             # On Windows the inc_path will use '/' for directory separator,
77             # but when looking for a module, we need to use the OS's separator.
78 13         24 my $partial_path = _mod_to_partial_path($pkg);
79              
80 13         23 my @paths;
81              
82 13         26 for(@INC) {
83 47 100       93 if(ref $_) {
84 9         33 my $ret = coderefs_in_INC($_, $inc_path);
85              
86             next
87 9 50       24 unless defined $ret;
88              
89 9 100       17 croak("invalid \@INC subroutine return $ret")
90             unless acts_like_fh($ret);
91              
92 6         2441 return $ret;
93             }
94              
95 38         140 my $fullpath = catfile($_, $partial_path);
96 38 100       828 push(@paths, $fullpath) if -f $fullpath;
97             }
98              
99 4 100       15 return unless @paths > 0;
100              
101 2 50       9 return wantarray ? @paths : $paths[0];
102             }
103              
104             sub mod_to_path {
105 16     16 1 27 my $pkg = shift;
106 16         22 my $path = $pkg;
107              
108 16 100       312 croak("Invalid package name '$pkg'")
109             unless $pkg =~ $Module::Locate::PkgRe;
110              
111             # %INC always uses / as a directory separator, even on Windows
112 15         71 $path =~ s!::!/!g;
113 15 50       49 $path .= '.pm' unless $path =~ m!\.pm$!;
114              
115 15         36 return $path;
116             }
117              
118             sub coderefs_in_INC {
119 9     9 0 19 my($path, $c) = reverse @_;
120              
121 9 50       50 my $ret = ref($c) eq 'CODE' ?
    100          
    100          
122             $c->( $c, $path )
123             :
124             ref($c) eq 'ARRAY' ?
125             $c->[0]->( $c, $path )
126             :
127             UNIVERSAL::can($c, 'INC') ?
128             $c->INC( $path )
129             :
130             warn("invalid reference in \@INC '$c'")
131             ;
132              
133 9         301 return $ret;
134             }
135              
136             sub acts_like_fh {
137 5     5   30 no strict 'refs';
  5         7  
  5         2110  
138             return ( ref $_[0] and (
139             ( ref $_[0] eq 'GLOB' and defined *{$_[0]}{IO} )
140             or ( UNIVERSAL::isa($_[0], 'IO::Handle') )
141             or ( overload::Method($_[0], '<>') )
142 19   66 19 1 2678 ) or ref \$_[0] eq 'GLOB' and defined *{$_[0]}{IO} );
143             }
144              
145             sub is_mod_loaded {
146 3     3 1 14 my $mod = shift;
147            
148 3 50       31 croak("Invalid package name '$mod'")
149             unless $mod =~ $Module::Locate::PkgRe;
150            
151             ## it looks like %INC entries automagically use / as a separator
152 3         17 my $path = join '/', split '::' => "$mod.pm";
153              
154 3   66     31 return (exists $INC{$path} && defined $INC{$path});
155             }
156              
157             sub _mod_to_partial_path {
158 13     13   16 my $package = shift;
159              
160 13         76 return catfile(split(/::/, $package)).'.pm';
161             }
162              
163             sub is_pkg_loaded {
164 3     3 1 6 my $pkg = shift;
165              
166 3 50       25 croak("Invalid package name '$pkg'")
167             unless $pkg =~ $Module::Locate::PkgRe;
168              
169 3         22 my @tbls = map "${_}::", split('::' => $pkg);
170 3         7 my $tbl = \%main::;
171            
172 3         8 for(@tbls) {
173 5 100       16 return unless exists $tbl->{$_};
174 4         27 $tbl = $tbl->{$_};
175             }
176            
177 2         10 return !!$pkg;
178             }
179             }
180              
181             q[ That better be make-up, and it better be good ];
182              
183             =pod
184              
185             =head1 NAME
186              
187             Module::Locate - locate modules in the same fashion as C and C
188              
189             =head1 SYNOPSIS
190              
191             use Module::Locate qw/ locate get_source /;
192            
193             add_plugin( locate "This::Module" );
194             eval 'use strict; ' . get_source('legacy_code.plx');
195              
196             =head1 DESCRIPTION
197              
198             Using C, return the path that C would find for a given
199             module or filename (it can also return a filehandle if a reference in C<@INC>
200             has been used). This means you can test for the existence, or find the path
201             for, modules without having to evaluate the code they contain.
202              
203             This module also comes with accompanying utility functions that are used within
204             the module itself (except for C) and are available for import.
205              
206             =head1 FUNCTIONS
207              
208             =over 4
209              
210             =item C
211              
212             Given function names, the appropriate functions will be exported into the
213             caller's package.
214              
215             If C<:all> is passed then all subroutines are exported.
216              
217             The B and B options are no longer supported.
218             See the BUGS section below.
219              
220              
221             =item C
222              
223             Given a module name as a string (in standard perl bareword format) locate the
224             path of the module. If called in a scalar context the first path found will be
225             returned, if called in a list context a list of paths where the module was
226             found. Also, if references have been placed in C<@INC> then a filehandle will
227             be returned, as defined in the C documentation. An empty C is
228             used if the module couldn't be located.
229              
230             As of version C<1.7> a filename can also be provided to further mimic the lookup
231             behaviour of C/C.
232              
233             =item C
234              
235             When provided with a package name, gets the path using C.
236             If C returned a path, then the contents of that file are returned
237             by C in a scalar.
238              
239             =item C
240              
241             Given a scalar, check if it behaves like a filehandle. Firstly it checks if it
242             is a bareword filehandle, then if it inherits from C and lastly if
243             it overloads the CE> operator. If this is missing any other standard
244             filehandle behaviour, please send me an e-mail.
245              
246             =item C
247              
248             Given a module name,
249             converts it to a relative path e.g C would become C.
250              
251             Note that this path will always use '/' for the directory separator,
252             even on Windows,
253             as that's the format used in C<%INC>.
254              
255             =item C
256              
257             Given a module name, return true if the module has been
258             loaded (i.e exists in the C<%INC> hash).
259              
260             =item C
261              
262             Given a package name (like C), check if the package has an existing
263             symbol table loaded (checks by walking the C<%main::> stash).
264              
265             =back
266              
267             =head1 SEE ALSO
268              
269             A review of modules that can be used to get the path (and often other information)
270             for one or more modules: L.
271              
272             L and L.
273              
274             =head1 REPOSITORY
275              
276             L
277              
278             =head1 BUGS
279              
280             In previous versions of this module, if you specified C 1>
281             when use'ing this module,
282             then looking up a module's path would update C<%INC>,
283             even if the module hadn't actually been loaded (yet).
284             This meant that if you subsequently tried to load the module,
285             it would wrongly not be loaded.
286              
287             Bugs are tracked using RT (bug you can also raise Github issues if you prefer):
288              
289             L
290              
291             =head1 AUTHOR
292              
293             Dan Brook C<< >>
294              
295             =head1 LICENSE
296              
297             This is free software; you can redistribute it and/or modify it under the same terms as
298             Perl itself.
299              
300             =cut