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   2845 use strict;
  5         11  
  5         157  
3              
4 5     5   22 use vars qw( $VERSION $NO_EXIT );
  5         7  
  5         4826  
5             $VERSION = '0.16';
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         5 print "$pkg\n";
132 1 50       10 @_ or print "\tNot found\n";
133 1         2 for my $module ( @_ ) {
134 2   50     23 printf "\t%s: %s\n", $module->file, $module->version || '?';
135             }
136             }
137              
138             sub import {
139 1     1   481 shift;
140 1 50       3 @_ or push @_, 'V';
141              
142 1         2 for my $pkg ( @_ ) {
143 1         4 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 4781 my( $pkg ) = @_;
151 5         23 my( $first ) = V::Module::Info->all_installed( $pkg );
152 5 50       34 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   16 my($proto, $file) = @_;
168 8   33     59 my($class) = ref $proto || $proto;
169              
170 8 50       90 return unless -r $file;
171              
172 8         25 my $self = {};
173 8         166 $self->{file} = File::Spec->rel2abs($file);
174 8         65 $self->{dir} = '';
175 8         13 $self->{name} = '';
176              
177 8         21 return bless $self, $class;
178             }
179              
180             sub all_installed {
181 6     6   14 my($proto, $name, @inc) = @_;
182 6   33     29 my($class) = ref $proto || $proto;
183              
184 6 50       32 @inc = @INC unless @inc;
185 6         80 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       116 next if ref $dir;
191              
192 60         360 my $filename = File::Spec->catfile($dir, $file);
193 60 100       891 if( -r $filename ) {
194 8         28 my $module = $class->new_from_file($filename);
195 8         83 $module->{dir} = File::Spec->rel2abs($dir);
196 8         20 $module->{name} = $name;
197 8         20 push @modules, $module;
198             }
199             }
200              
201 6         59 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       293 open(my $mod, '<', $parsefile) or die "open($parsefile): $!";
211              
212 7         32 my $inpod = 0;
213 7         15 my $result;
214 7         11 local $_;
215 7         217 while (<$mod>) {
216 26 50       98 $inpod = /^=(?!cut)/ ? 1 : /^=cut/ ? 0 : $inpod;
    50          
217 26 50 33     76 next if $inpod || /^\s*#/;
218              
219 26         33 chomp;
220 26         25 my $eval;
221 26 100       103 if (m/([\$*])(([\w\:\']*)\bVERSION)\b.*\=/) {
    100          
222 5         6 { local($1, $2); ($_ = $_) = m/(.*)/; } # untaint
  5         20  
  5         21  
223 5         20 $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         11 $eval = qq{
236             package V::Module::Info::_version $1;
237             V::Module::Info::_version->VERSION;;
238             };
239             }
240 26 100       55 if (defined($eval)) {
241 7         25 local $^W = 0;
242 7     3   565 $result = eval($eval);
  3     1   17  
  3     1   4  
  3         132  
  1         5  
  1         1  
  1         29  
  1         5  
  1         2  
  1         42  
243 7 50       53 warn "Could not eval '$eval' in $parsefile: $@" if $@;
244 7 50       21 $result = "undef" unless defined $result;
245              
246             # use the version modulue to deal with v-strings
247 7         1641 require version;
248 7         6477 $result = version->parse($result);
249 7         25 last;
250             }
251             }
252 7         109 close($mod);
253 7         110 return $result;
254             }
255              
256             sub accessor {
257 9     9   12 my $self = shift;
258 9         11 my $field = shift;
259              
260 9 50       30 $self->{ $field } = $_[0] if @_;
261 9         28 return $self->{ $field };
262             }
263              
264             sub AUTOLOAD {
265 17     17   45 my( $self ) = @_;
266              
267 5     5   44 use vars qw( $AUTOLOAD );
  5         9  
  5         562  
268 17         82 my( $method ) = $AUTOLOAD =~ m|.+::(.+)$|;
269              
270 17 100       110 if ( exists $self->{ $method } ) {
271 9         23 splice @_, 1, 0, $method;
272 9         28 goto &accessor;
273             }
274             }