File Coverage

blib/lib/Module/Versions/Report.pm
Criterion Covered Total %
statement 30 40 75.0
branch 16 28 57.1
condition 3 15 20.0
subroutine 1 3 33.3
pod 2 2 100.0
total 52 88 59.0


line stmt bran cond sub pod time code
1              
2             require 5;
3             package Module::Versions::Report;
4             $VERSION = '1.06';
5             $PACKAGES_LIMIT = 10000;
6              
7             =head1 NAME
8              
9             Module::Versions::Report -- report versions of all modules in memory
10              
11             =head1 SYNOPSIS
12              
13             use Module::Versions::Report;
14            
15             ...and any code you want...
16              
17             This will run all your code normally, but then as the Perl
18             interpreter is about to exit, it will print something
19             like:
20              
21             Perl v5.6.1 under MSWin32.
22             Modules in memory:
23             attributes;
24             AutoLoader v5.58;
25             Carp;
26             Config;
27             DynaLoader v1.04;
28             Exporter v5.562;
29             Module::Versions::Report v1.01;
30             HTML::Entities v1.22;
31             HTML::HeadParser v2.15;
32             HTML::Parser v3.25;
33             [... and whatever other modules were loaded that session...]
34              
35             Consider its use from the command line:
36              
37             % perl -MModule::Versions::Report -MLWP -e 1
38              
39             Perl v5.6.1 under MSWin32.
40             Modules in memory:
41             attributes;
42             AutoLoader v5.58;
43             [...]
44              
45             =head1 DESCRIPTION
46              
47             I often get email from someone reporting a bug in a module I've
48             written. I email back, asking what version of the module it is,
49             what version of Perl on what OS, and sometimes what version of
50             some relevent third library (like XML::Parser). They reply,
51             saying "Perl 5". I say "I need the exact version, as reported
52             by C". They tell me. And I say "I, uh, also asked about
53             the version of my module and XML::Parser [or whatever]". They say
54             "Oh yeah. It's 2.27". "Is that my module or XML::Parser?"
55             "XML::Parser." "OK, and what about my module's
56             version?" "Ohyeah. That's 3.11." By this time, days have passed,
57             and what should have been a simple operation -- reporting the version
58             of Perl and relevent modules, has been needlessly complicated.
59              
60             This module is for simplifying that task. If you add "use
61             Module::Versions::Report;" to a program (especially handy if your
62             program is one that demonstrates a bug in some module), then when the
63             program has finished running, you well get a report detailing the all
64             modules in memory, and noting the version of each (for modules that
65             defined a C<$VERSION>, at least).
66              
67             =head1 USING
68              
69             =head2 Importing
70              
71             If this package is imported then END block is set, and report printed to
72             stdout on a program exit, so use C if you
73             need a report on exit or C otherwise
74             and call report or print_report functions yourself.
75              
76             =cut
77              
78             $Already = 0;
79              
80             sub import {
81             # so "use Module::Versions::Report;" sets up the END block, but
82             # a mere "use Module::Versions::Report ();" doesn't.
83 0 0   0   0 unless($Already) {
84 0         0 eval 'END { print_report(); }';
85 0 0       0 die "Extremely unexpected error in ", __PACKAGE__, ": $@" if $@;
86 0         0 $Already = 1;
87             }
88 0         0 return;
89             }
90              
91             =head2 report and print_report functions
92              
93             The first one returns preformatted report as a string, the latter outputs
94             a report to stdout.
95              
96             =cut
97              
98             sub report {
99 1     1 1 167836 my @out;
100 1 50 33     44 push @out,
    50          
    50          
101             "\n\nPerl v",
102             defined($^V) ? sprintf('%vd', $^V) : $],
103             " under $^O ",
104             (defined(&Win32::BuildNumber) and defined &Win32::BuildNumber())
105             ? ("(Win32::BuildNumber ", &Win32::BuildNumber(), ")") : (),
106             (defined $MacPerl::Version)
107             ? ("(MacPerl version $MacPerl::Version)") : (),
108             "\n"
109             ;
110              
111             # Ugly code to walk the symbol tables:
112 1         4 my %v;
113 1         2 my @stack = (''); # start out in %::
114 1         3 my $this;
115 1         3 my $count = 0;
116 1         1 my $pref;
117 1         6 while(@stack) {
118 201         336 $this = shift @stack;
119 201 50       942 die "Too many packages?" if $count > $PACKAGES_LIMIT;
120 201 50       1291 next if exists $v{$this};
121 201 100       380 next if $this eq 'main'; # %main:: is %::
122              
123             #print "Peeking at $this => ${$this . '::VERSION'}\n";
124            
125 200 100 33     230 if(defined ${$this . '::VERSION'} ) {
  200 50 0     3648  
  141   33     1466  
126 59         72 $v{$this} = ${$this . '::VERSION'};
  59         576  
127 59         466 $count++;
128             } elsif(
129 0         0 defined *{$this . '::ISA'} or defined &{$this . '::import'}
  0         0  
130             # without perl version check on MacOS X's defualt perl things may seg fault
131             # for example Request Tracker 3.8's make test target fails additional tests
132 0 0 0     0 or ($this ne '' and grep { ($] < 5.010 or ref $_ eq 'GLOB') and defined *{$_}{'CODE'} }
  0         0  
133             values %{$this . "::"})
134             # If it has an ISA, an import, or any subs...
135             ) {
136             # It's a class/module with no version.
137 141         1586 $v{$this} = undef;
138 141         1068 $count++;
139             } else {
140             # It's probably an unpopulated package.
141             ## $v{$this} = '...';
142             }
143            
144 200 100       1752 $pref = length($this) ? "$this\::" : '';
145 200 100       299 push @stack, map m/^(.+)::$/ ? "$pref$1" : (), keys %{$this . '::'};
  200         14865  
146             #print "Stack: @stack\n";
147             }
148 1         4 push @out, " Modules in memory:\n";
149 1         4 delete @v{'', ''};
150 1         70 foreach my $p (sort {lc($a) cmp lc($b)} keys %v) {
  1261         1989  
151             #$indent = ' ' x (2 + ($p =~ tr/:/:/));
152 198 100       958 push @out, ' ',
153             # $indent,
154             $p, defined($v{$p}) ? " v$v{$p};\n" : ";\n";
155             }
156 1         85 push @out, sprintf "[at %s (local) / %s (GMT)]\n",
157             scalar(localtime), scalar(gmtime);
158 1         372 return join '', @out;
159             }
160              
161 0     0 1   sub print_report { print '', report(); }
162              
163             1;
164              
165             =head1 COPYRIGHT AND DISCLAIMER
166              
167             Copyright 2001-2003 Sean M. Burke. This library is free software; you
168             can redistribute it and/or modify it under the same terms as Perl
169             itself.
170              
171             This program is distributed in the hope that it will be useful, but
172             without any warranty; without even the implied warranty of
173             merchantability or fitness for a particular purpose.
174              
175             =head1 MAINTAINER
176              
177             Ruslan U. Zakirov Eruz@bestpractical.comE
178              
179             =head1 AUTHOR
180              
181             Sean M. Burke, Esburke@cpan.orgE
182              
183             =cut
184              
185             __END__