File Coverage

blib/lib/Lib/Module.pm
Criterion Covered Total %
statement 24 252 9.5
branch 0 94 0.0
condition 0 18 0.0
subroutine 8 35 22.8
pod 9 26 34.6
total 41 425 9.6


line stmt bran cond sub pod time code
1             package Lib::Module;
2             # $Id: Module.pm,v 1.13 2004/03/28 02:22:23 kiesling Exp $
3             $VERSION=0.70;
4 1     1   8823 use vars qw( @ISA @EXPORT @EXPORT_OK $VERSION );
  1         2  
  1         133  
5             push @ISA, qw(Exporter);
6              
7             @EXPORT_OK = qw($VERSION &libdirs &module_paths &scanlibs &retrieve
8             &pathname &usesTk &ModuleVersion &PathName &BaseName
9             &PackageName &Supers);
10              
11             require Exporter;
12             require Carp;
13 1     1   7 use File::Basename;
  1         2  
  1         128  
14 1     1   584 use Lib::ModuleSymbol;
  1         3  
  1         53  
15 1     1   589 use Lib::SymbolRef;
  1         3  
  1         53  
16 1     1   1170 use IO::Handle;
  1         8782  
  1         58  
17 1     1   1174 use DB;
  1         3992  
  1         121  
18              
19             my @modulepathnames;
20             my @libdirectories;
21              
22             =head1 NAME
23              
24             Lib::Module.pm - Perl library module utilities.
25              
26             =head1 SYNOPSIS
27              
28             use Lib::Module;
29              
30             my $m = new Lib::Module; # Create a module object.
31              
32             # Create the class library hierarchy.
33             $m -> libdirs ($verbose);
34             $m -> module_paths ($verbose);
35             $m -> scanlibs ($verbose);
36              
37             # Retrieve the module object for a package.
38             my $m2 = $m -> retrieve ("Tk::Browser");
39              
40             print $m2 -> PathName . "\n" .
41             $m2 -> BaseName . "\n" .
42             $m2 -> PackageName . "\n" .
43             $m2 -> ModuleVersion . "\n" .
44             $m2 -> Supers . "\n";
45              
46             # Return the file path name of a module.
47             my $path = $m -> pathname ("Tk::Browser");
48              
49              
50              
51             =head1 DESCRIPTION
52              
53             A Lib::Module object describes a Perl library module and includes the
54             module's package name, file name, version, and superclasses, if any.
55              
56             The module objects are normally part of a class hierarchy generated by
57             libdirs (), module_paths (), and scanlibs (). Every module is a
58             subclass of UNIVERSAL, Perl's default superclass.
59              
60             =head1 METHODS
61              
62             =head2 ModuleVersion
63              
64             Return the module's b<$VERSION => line.
65              
66             =head2 PathName ($name)
67              
68             Return the module's path.
69              
70             =head2 BaseName ($name)
71              
72             Return the module's file basename.
73              
74             =head2 PackageName ($name)
75              
76             Return the argument of the module's B function.
77              
78             =head2 retrieve (I || I)
79              
80             The retrieve ($name) method returns the Lib::Module object or undef.
81              
82             my $new = $m -> retrieve ("Optional::Module");
83              
84             if (!defined $new) {
85             print "Can't find Optional::Module.\n"
86             }
87              
88             B matches the first part of the module's name. If B
89             doesn't match a sub-module, specify only the sub-module's name; e.g.,
90             'Module' instead of 'Optional::Module'.
91              
92             =head2 Supers ()
93              
94             Returns the module's superclasses; i.e, the arguments of an @ISA
95             declaration.
96              
97             =head1 EXPORTS
98              
99             See the @EXPORTS_OK array.
100              
101             =head1 BUGS
102              
103             Does not take into account all of the possible module naming schemes
104             when retrieving modules.
105              
106             =head1 VERSION
107              
108             VERSION 0.69
109              
110             =head1 COPYRIGHT
111              
112             Copyright © 2001-2004 Robert Kiesling, rkies@cpan.org.
113              
114             Licensed under the same terms as Perl. Refer to the file,
115             "Artistic," for information.
116              
117             =head1 SEE ALSO
118              
119             perl(1), Tk::Browser(3)
120              
121             =cut
122              
123             sub new {
124 0     0 0   my $proto = shift;
125 0   0       my $class = ref( $proto ) || $proto;
126 0           my $self = {
127             children => [],
128             parents => '',
129             pathname => '',
130             basename => '',
131             packagename => '',
132             version => '',
133             superclasses => undef,
134             baseclass => '',
135             moduleinfo => undef,
136             symbols => []
137             };
138 0           bless( $self, $class);
139 0           return $self;
140             }
141              
142             # Given a file base name, return the Module object.
143 1     1   9 no warnings;
  1         3  
  1         256  
144             sub retrieve {
145 0     0 1   my $parent = shift;
146 0           my ($n) = @_;
147 0 0 0       if ( $parent -> {basename} =~ /^$n$/ || $_ -> {packagename} =~ /^$n$/) {
148 0           return $parent;
149             }
150 0           foreach ( @{$parent -> {children}} ) {
  0            
151 0 0 0       return $_
152             if ( $_ -> {basename} =~ /^$n$/ || $_ -> {packagename} =~ /^$n/);
153             }
154 0   0       foreach ( @{$parent -> {children}} && $_ -> {packagename} =~ /^$n/) {
  0            
155 0 0         return $_ if (retrieve( $_, $n ));
156             }
157 0           return undef;
158             }
159 1     1   6 use warnings;
  1         2  
  1         2455  
160              
161             sub pathname {
162 0     0 0   my $self = shift;
163 0           my $name = $_[0];
164 0           my $verbose = $_[1];
165 0 0         autoflush STDOUT 1 if $verbose;
166 0 0 0       if ($self -> {basename} =~ /^$name/ || $self->{packagename} =~ /^$name/) {
167 0           return $self -> {pathname}; }
168 0           foreach ( @{$self -> {children}} ) {
  0            
169 0 0         print '.' if $verbose;
170 0 0 0       if ($_ -> {basename} =~ /^$name/ || $self->{packagename} =~ /^$name/) {
171 0           return $_ -> {pathname};
172             }
173             }
174 0           foreach ( @{$self -> {children}} ) {
  0            
175 0 0         if ( pathname ( $_, $name ) ) {
176 0           return $_ -> {pathname}; }
177             }
178 0           return undef;
179             }
180              
181             # Given a module package or sub-package name, return the module object.
182             # It's probably desirable to use this in preference to retrieve,
183             # with external calls, to avoid dealing with the library pathnames
184             # unless necessary.
185             sub retrieve_module {
186 0     0 0   my $parent = shift;
187 0           my ($n) = @_;
188 0 0         if ( $parent -> {packagename} eq $n ) {
189 0           return $parent; }
190 0           foreach ( @{$parent -> {children}} ) {
  0            
191 0 0         if ( $_ -> {packagename} eq $n ) {
192 0           return $_;
193             }
194             }
195 0           foreach ( @{$parent -> {children}} ) {
  0            
196 0 0         if ( retrieve( $_, $n ) ) {
197 0           return $_; }
198             }
199 0           return undef;
200             }
201              
202             sub modulepathnames {
203 0     0 0   my $self = shift;
204 0           return @modulepathnames;
205             }
206              
207             sub libdirectories {
208 0     0 0   my $self = shift;
209 0           return @libdirectories;
210             }
211              
212             sub scanlibs {
213 0     0 0   my $b = shift;
214 0           my $verbose = $_[0];
215 0           my $m;
216 0           my ($path, $bname, $ext);
217 0 0         autoflush STDOUT 1 if $verbose;
218 0           LOOP: foreach my $i ( @modulepathnames ) {
219 0 0         print '.' if $verbose;
220 0           ($bname, $path, $ext) = fileparse($i, qw(\.pm$ \.pl$) );
221             # Don't use RCS Archives or Emacs bacups
222 0 0         if( $bname =~ /(,v)|~/ ) { next LOOP; }
  0            
223 0 0         if( $bname =~ /UNIVERSAL/ ) {
224 0           $b -> modinfo( $i );
225             } else {
226 0           $m = new Lib::Module;
227 0 0         next LOOP if ! $m -> modinfo( $i );
228 0           $m -> {parents} = $b;
229 0           push @{$b -> {children}}, ($m);
  0            
230             }
231             }
232             }
233              
234             sub modinfo {
235 0     0 0   my $self = shift;
236 0           my ($path) = @_;
237 0           my ($dirs, $bname, $ext);
238 0           my ($supers, $pkg, $ver, @text, @matches);
239 0           ($bname, $dirs, $ext) = fileparse($path, qw(\.pm \.pl));
240 0           $self -> {pathname} = $path;
241 0           @text = $self -> readfile;
242 0           my $p = new Lib::ModuleSymbol;
243 0           $p -> {pathname} = $path;
244 0           $p -> text_symbols( @text );
245 0 0         $self -> {version} = $p -> {version} if $p -> {version};
246 0           $self -> {moduleinfo} = $p ;
247 0           $self -> {packagename} = $p -> {packagename};
248             # We do a static match here because it's faster
249             # Todo: include base classes from "use base" statements.#
250 0           @matches = grep /^(our|my|push)+\s+\@ISA(.*?)\;/, @text;
251 0           $supers = $matches[0];
252 0 0         $supers =~ s/\@ISA|push|our|my|(qw)|[=\(\)\;]//gms if $supers;
253 0 0         $supers =~ s/\W*// if $supers;
254 0           $self -> {basename} = $bname;
255 0           $self -> {superclasses} = $supers;
256 0           return 1;
257             }
258              
259             # See the perlmod manpage
260             # Returns a hash of symbol => values.
261             # Handles as separate ref.
262             # Typeglob dereferencing deja Symdump.pm and dumpvar.pl, et al.
263             # Package namespace creation and module loading per base.pm.
264             sub exportedkeys {
265 0     0 0   my $m = shift;
266 0           my ($pkg) = @_;
267 0           my $obj;
268 0           my $key; my $val;
269 0           my $rval;
270 0           my $nval;
271 0           my %keylist = ();
272 0           $m -> {symbols} = ();
273 0           my @vallist;
274 0           my $i = 0;
275 0           EACHKEY: foreach $key( keys %{*{"$pkg"}} ) {
  0            
  0            
276 0 0         next unless $key;
277 0 0         if( defined ($val = ${*{"$pkg"}}{$key} ) ) {
  0            
  0            
278 0           $rval = $val; $nval = $val;
  0            
279 0           $obj = tie $rval, 'Lib::SymbolRef', $nval;
280 0           push @{$m -> {symbols}}, ($obj);
  0            
281 0 0         foreach( @vallist) { if ( $_ eq $rval ) { next EACHKEY } }
  0            
  0            
282             # Replace the static $VERSION and @ISA values
283             # of the initial library scan with the symbol
284             # compile/run-time values.
285 0           local (*v) = $val;
286             # Look for the stash values in case they've changed
287             # from the source scan.
288 0 0         if( $key =~ /VERSION/ ) {
289 0           $m -> {version} = ${*v{SCALAR}};
  0            
290             }
291 0 0         if($key =~ /ISA/ ) {
292 0           $m -> {superclasses} = "@{*v{ARRAY}}";
  0            
293             }
294             }
295             }
296 0 0         $keylist{$key} = ${*{"$pkg"}}{$key} if $key;
  0            
  0            
297             # for dumping symbol refs to STDOUT.
298             # example of how to print listing of symbol refs.
299             # foreach my $i ( @{$m -> {symbols}} ) {
300             # foreach( @{$i -> {name}} ) {
301             # print $_;
302             # }
303             # print "\n--------\n";
304             # }
305 0           return %keylist;
306             }
307              
308             #
309             # Here for example only. This function (or the statements
310             # it contains), must be in the package that has the main:: stash
311             # space in order to list the packages symbols into the correct
312             # stash context.
313             #
314             # sub modImport {
315             # my ($pkg) = @_;
316             # eval "package $pkg";
317             # eval "use $pkg";
318             # eval "require $pkg";
319             #}
320              
321             sub readfile {
322 0     0 0   my $self = shift;
323 0           my $fn;
324 0 0         if (@_){ ($fn) = @_; } else { $fn = $self -> PathName; }
  0            
  0            
325 0           my @text;
326 0 0         open FILE, $fn or warn "Couldn't open file $fn: $!.\n";
327 0           @text = ;
328 0           close FILE;
329 0           return @text;
330             }
331              
332             # de-allocate module and all its children
333             sub DESTROY ($) {
334 0     0     my ($m) = @_;
335 0           @c = $m -> {children};
336 0           $d = @c;
337 0 0         if ( $d == 0 ) {
338 0           $m = {
339             children => undef
340             };
341 0           return;
342             }
343 0           foreach my $i ( @{$m -> {children}} ) {
  0            
344 0           Lib::Module -> DESTROY($i);
345             }
346             }
347              
348             sub libdirs {
349 0     0 0   my $self = shift;
350 0           my $verbose = $_[0];
351 0           my $f; my $f2;
352 0           my $d;
353 0 0         autoflush STDOUT 1 if $verbose;
354 0           foreach $d ( @INC ) {
355 0           push @libdirectories, ($d);
356 0 0         print '.' if $verbose;
357 0           opendir DIR, $d;
358 0           @dirfiles = readdir DIR;
359 0           closedir DIR;
360             # look for subdirs of the directories in @INC.
361 0           foreach $f ( @dirfiles ) {
362 0 0         next if $f =~ m/^\.{1,2}$/ ;
363 0           $f2 = $d . '/' . $f;
364 0 0         if (opendir SUBDIR, $f2 ) {
365 0           push @libdirectories, ($f2);
366 0 0         print '.' if $verbose;
367 0           libsubdir( $f2 );
368 0           closedir SUBDIR;
369             }
370             }
371             }
372             }
373              
374             sub libsubdir {
375 0     0 0   my ($parent) = @_;
376 0           opendir DIR, $parent;
377 0           my @dirfiles = readdir DIR;
378 0           closedir DIR;
379 0           foreach (@dirfiles) {
380 0 0         next if $_ =~ m/^\.{1,2}$/ ;
381 0           my $f2 = $parent . '/' . $_;
382 0 0         if (opendir SUBDIR, $f2 ) {
383 0           push @libdirectories, ($f2);
384 0 0         print '.' if $verbose;
385 0           libsubdir( $f2 );
386 0           closedir SUBDIR;
387             }
388             }
389             }
390              
391             sub module_paths {
392 0     0 0   my $self = shift;
393 0           my ($f, $pathname, @allfiles);
394 0           foreach ( @libdirectories ) {
395 0           opendir DIR, $_;
396 0           @allfiles = readdir DIR;
397 0           closedir DIR;
398 0           foreach $f ( @allfiles ) {
399 0 0         if ( $f =~ /\.p[lm]/ ) {
400 0           $pathname = $_ . '/' . $f;
401 0           push @modulepathnames, ($pathname);
402             }
403             }
404             }
405             }
406              
407             sub Children {
408 0     0 0   my $self = shift;
409 0 0         if (@_) { $self -> {children} = shift; }
  0            
410 0           return $self -> {children}
411             }
412              
413             sub Parents {
414 0     0 0   my $self = shift;
415 0 0         if (@_) { $self -> {parents} = shift; }
  0            
416 0           return $self -> {parents}
417             }
418              
419             sub PathName {
420 0     0 1   my $self = shift;
421 0 0         if (@_) { $self -> {pathname} = shift; }
  0            
422 0           return $self -> {pathname}
423             }
424              
425             sub BaseName {
426 0     0 1   my $self = shift;
427 0 0         if (@_) { $self -> {basename} = shift; }
  0            
428 0           return $self -> {basename}
429             }
430              
431             sub ModuleVersion {
432 0     0 1   my $self = shift;
433 0           return $self -> {moduleinfo} -> {version};
434             }
435              
436             sub PackageName {
437 0     0 1   my $self = shift;
438 0 0         if (@_) { $self -> {packagename} = shift; }
  0            
439 0           return $self -> {packagename}
440             }
441              
442             sub Symbols {
443 0     0 1   my $self = shift;
444 0 0         if (@_) { $self -> {symbols} = shift; }
  0            
445 0           return $self -> {symbols}
446             }
447              
448             ###
449             ### Version, SuperClass -- Module.pm uses hashref directly.
450             ###
451             sub Version {
452 0     0 1   my $self = shift;
453 0 0         if (@_) { $self -> {version} = shift; }
  0            
454 0           return $self -> {version}
455             }
456              
457             sub SuperClasses {
458 0     0 0   my $self = shift;
459 0 0         if (@_) { $self -> {superclasses} = shift; }
  0            
460 0           return $self -> {superclasses}
461             }
462              
463             sub BaseClass {
464 0     0 0   my $self = shift;
465 0 0         if (@_) { $self -> {baseclass} = shift; }
  0            
466 0           return $self -> {baseclass}
467             }
468              
469             sub ModuleInfo {
470 0     0 0   my $self = shift;
471 0 0         if (@_) { $self -> {moduleinfo} = shift; }
  0            
472 0           return $self -> {moduleinfo}
473             }
474              
475             sub Supers {
476 0     0 1   my $self = shift;
477 0           return $self -> {superclasses};
478             }
479              
480             sub Import {
481 0     0 1   my ($pkg) = @_;
482 0           &Exporter::import( $pkg );
483             }
484              
485             1;
486