File Coverage

blib/lib/V.pm
Criterion Covered Total %
statement 90 90 100.0
branch 24 38 63.1
condition 4 11 36.3
subroutine 14 14 100.0
pod 2 2 100.0
total 134 155 86.4


line stmt bran cond sub pod time code
1             package V;
2 5     5   2751 use strict;
  5         10  
  5         143  
3              
4 5     5   20 use vars qw( $VERSION $NO_EXIT );
  5         8  
  5         5180  
5             $VERSION = '0.15_01';
6              
7             $NO_EXIT ||= 0; # prevent import() from exit()ing and fall of the edge
8              
9             =head1 NAME
10              
11             V - Print version of the specified module(s).
12              
13             =head1 SYNOPSIS
14              
15             $ perl -MV=V
16              
17             or if you want more than one
18              
19             $ perl -MV=CPAN,V
20              
21             Can now also be used as a light-weight module for getting versions of
22             modules without loading them:
23              
24             require V;
25             printf "%s has version '%s'\n", "V", V::get_version( "V" );
26              
27             If you want all available files/versions from C<@INC>:
28              
29             require V;
30             my @all_V = V::Module::Info->all_installed("V");
31             printf "%s:\n", $all_V[0]->name;
32             printf "\t%-50s - %s\n", $_->file, $_->version
33             for @all_V;
34              
35             Each element in that array isa C object with 3 attributes and a method:
36              
37             =over
38              
39             =item I B
40              
41             The package name.
42              
43             =item I B
44              
45             Full filename with directory.
46              
47             =item I B
48              
49             The base directory (from C<@INC>) where the package-file was found.
50              
51             =item I B
52              
53             This method will look through the file to see if it can find a version
54             assignment in the file and uses that determine the version. As of version
55             0.13_01, all versions found are passed through the L module.
56              
57             =back
58              
59             =head1 DESCRIPTION
60              
61             This module uses stolen code from L to find the location
62             and version of the specified module(s). It prints them and exit()s.
63              
64             It defines C and is based on an idea from Michael Schwern
65             on the perl5-porters list. See the discussion:
66              
67             https://www.nntp.perl.org/group/perl.perl5.porters/2002/01/msg51007.html
68              
69             =head2 V::get_version($pkg)
70              
71             Returns the version of the first available file for this package as found by
72             following C<@INC>.
73              
74             =head3 Arguments
75              
76             =over
77              
78             =item 1. $pkg
79              
80             The name of the package for which one wants to know the version.
81              
82             =back
83              
84             =head3 Response
85              
86             This C returns the version of the file that was first found
87             for this package by following C<@INC> or C if no file was found.
88              
89             =begin implementation
90              
91             =head2 report_pkg
92              
93             This sub prints the results for a package.
94              
95             =head3 Arguments
96              
97             =over
98              
99             =item 1. $pkg
100              
101             The name of the package that was probed for versions
102              
103             =item 2. @versions
104              
105             An array of Module-objects with full path and version.
106              
107             =back
108              
109             =end implementation
110              
111             =head1 AUTHOR
112              
113             Abe Timmerman C<< >>.
114              
115             =head1 COPYRIGHT & LICENSE
116              
117             Copyright 2002-2006 Abe Timmerman, All Rights Reserved.
118              
119             This library is free software; you can redistribute it and/or modify
120             it under the same terms as Perl itself.
121              
122             This program is distributed in the hope that it will be useful,
123             but WITHOUT ANY WARRANTY; without even the implied warranty of
124             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
125              
126             =cut
127              
128             sub report_pkg($@) {
129 1     1 1 2 my $pkg = shift;
130              
131 1         6 print "$pkg\n";
132 1 50       10 @_ or print "\tNot found\n";
133 1         2 for my $module ( @_ ) {
134 2   50     26 printf "\t%s: %s\n", $module->file, $module->version || '?';
135             }
136             }
137              
138             sub import {
139 1     1   440 shift;
140 1 50       3 @_ or push @_, 'V';
141              
142 1         2 for my $pkg ( @_ ) {
143 1         3 my @modules = V::Module::Info->all_installed( $pkg );
144 1         2 report_pkg $pkg, @modules;
145             }
146 1 50       4 exit() unless $NO_EXIT;
147             }
148              
149             sub get_version {
150 5     5 1 4262 my( $pkg ) = @_;
151 5         18 my( $first ) = V::Module::Info->all_installed( $pkg );
152 5 50       24 return $first ? $first->version : undef;
153             }
154              
155             caller or V->import( @ARGV );
156              
157             1;
158              
159             # Okay I did the AUTOLOAD() bit, but this is a Copy 'n Paste job.
160             # Thank you Michael Schwern for Module::Info! This one is mostly that!
161              
162             package V::Module::Info;
163              
164             require File::Spec;
165              
166             sub new_from_file {
167 8     8   19 my($proto, $file) = @_;
168 8   33     63 my($class) = ref $proto || $proto;
169              
170 8 50       94 return unless -r $file;
171              
172 8         30 my $self = {};
173 8         161 $self->{file} = File::Spec->rel2abs($file);
174 8         59 $self->{dir} = '';
175 8         12 $self->{name} = '';
176              
177 8         20 return bless $self, $class;
178             }
179              
180             sub all_installed {
181 6     6   14 my($proto, $name, @inc) = @_;
182 6   33     28 my($class) = ref $proto || $proto;
183              
184 6 50       36 @inc = @INC unless @inc;
185 6         73 my $file = File::Spec->catfile(split m/::/, $name) . '.pm';
186              
187 6         13 my @modules = ();
188 6         10 foreach my $dir (@inc) {
189             # Skip the new code ref in @INC feature.
190 60 50       115 next if ref $dir;
191              
192 60         351 my $filename = File::Spec->catfile($dir, $file);
193 60 100       991 if( -r $filename ) {
194 8         28 my $module = $class->new_from_file($filename);
195 8         83 $module->{dir} = File::Spec->rel2abs($dir);
196 8         19 $module->{name} = $name;
197 8         16 push @modules, $module;
198             }
199             }
200              
201 6         46 return @modules;
202             }
203              
204             # Thieved from ExtUtils::MM_Unix 1.12603
205             sub version {
206 7     7   12 my($self) = shift;
207              
208 7         33 my $parsefile = $self->file;
209              
210 7 50       260 open(my $mod, '<', $parsefile) or die "open($parsefile): $!";
211              
212 7         20 my $inpod = 0;
213 7         8 my $result;
214 7         9 local $_;
215 7         174 while (<$mod>) {
216 26 50       73 $inpod = /^=(?!cut)/ ? 1 : /^=cut/ ? 0 : $inpod;
    50          
217 26 50 33     77 next if $inpod || /^\s*#/;
218              
219 26         32 chomp;
220 26         23 my $eval;
221 26 100       96 if (m/([\$*])(([\w\:\']*)\bVERSION)\b.*\=/) {
    100          
222 5         7 { local($1, $2); ($_ = $_) = m/(.*)/; } # untaint
  5         18  
  5         21  
223 5         27 $eval = qq{
224             package V::Module::Info::_version;
225             no strict;
226              
227             local $1$2;
228             \$$2=undef; do {
229             $_
230             }; \$$2
231             };
232             }
233             # perl 5.12.0+
234             elsif (m/^\s* package \s+ [^\s]+ \s+ ([^;\{]+) [;\{]/x) {
235 2         9 $eval = qq{
236             package V::Module::Info::_version $1;
237             V::Module::Info::_version->VERSION;;
238             };
239             }
240 26 100       57 if (defined($eval)) {
241 7         22 local $^W = 0;
242 7     3   451 $result = eval($eval);
  3     1   17  
  3     1   6  
  3         139  
  1         6  
  1         1  
  1         30  
  1         6  
  1         2  
  1         30  
243 7 50       20 warn "Could not eval '$eval' in $parsefile: $@" if $@;
244 7 50       17 $result = "undef" unless defined $result;
245              
246             # use the version modulue to deal with v-strings
247 7         1473 require version;
248 7         6253 $result = version->parse($result);
249 7         21 last;
250             }
251             }
252 7         105 close($mod);
253 7         101 return $result;
254             }
255              
256             sub accessor {
257 9     9   12 my $self = shift;
258 9         10 my $field = shift;
259              
260 9 50       28 $self->{ $field } = $_[0] if @_;
261 9         31 return $self->{ $field };
262             }
263              
264             sub AUTOLOAD {
265 17     17   44 my( $self ) = @_;
266              
267 5     5   33 use vars qw( $AUTOLOAD );
  5         9  
  5         554  
268 17         81 my( $method ) = $AUTOLOAD =~ m|.+::(.+)$|;
269              
270 17 100       104 if ( exists $self->{ $method } ) {
271 9         21 splice @_, 1, 0, $method;
272 9         27 goto &accessor;
273             }
274             }