File Coverage

blib/lib/Module/Extract/VERSION.pm
Criterion Covered Total %
statement 48 50 96.0
branch 12 18 66.6
condition 7 9 77.7
subroutine 7 7 100.0
pod 1 1 100.0
total 75 85 88.2


line stmt bran cond sub pod time code
1             require v5.10;
2              
3             package Module::Extract::VERSION;
4 2     2   1495 use strict;
  2         3  
  2         60  
5              
6 2     2   11 use warnings;
  2         3  
  2         56  
7 2     2   9 no warnings;
  2         4  
  2         75  
8              
9 2     2   11 use Carp qw(carp);
  2         3  
  2         879  
10              
11             our $VERSION = '1.115';
12              
13             =encoding utf8
14              
15             =head1 NAME
16              
17             Module::Extract::VERSION - Extract a module version safely
18              
19             =head1 SYNOPSIS
20              
21             use Module::Extract::VERSION;
22              
23             my $version # just the version
24             = Module::Extract::VERSION->parse_version_safely( $file );
25              
26             my @version_info # extra info
27             = Module::Extract::VERSION->parse_version_safely( $file );
28              
29             =head1 DESCRIPTION
30              
31             This module lets you pull out of module source code the version number
32             for the module. It assumes that there is only one C<$VERSION>
33             in the file and the entire C<$VERSION> statement is on the same line.
34              
35             =cut
36              
37             =head2 Class methods
38              
39             =over 4
40              
41             =item $class->parse_version_safely( FILE );
42              
43             Given a module file, return the module version. This works just like
44             C in PAUSE. It looks for the single line that has the
45             C<$VERSION> statement, extracts it, evals it in a Safe compartment,
46             and returns the result.
47              
48             In scalar context, it returns just the version as a string. In list
49             context, it returns the list of:
50              
51             sigil
52             fully-qualified variable name
53             version value
54             file name
55             line number of $VERSION
56              
57             =cut
58              
59             sub parse_version_safely { # stolen from PAUSE's mldistwatch, but refactored
60 8     8 1 6565 my( $class, $file ) = @_;
61              
62 8         31 local $/ = "\n";
63 8         10 local $_; # don't mess with the $_ in the map calling this
64              
65 8         11 my $fh;
66 8 50       292 unless( open $fh, "<", $file ) {
67 0         0 carp( "Could not open file [$file]: $!\n" );
68 0         0 return;
69             }
70              
71 8         56 my $in_pod = 0;
72 8         16 my( $sigil, $var, $version, $line_number, $rhs );
73 8         162 while( <$fh> ) {
74 99         132 $line_number++;
75 99         117 chomp;
76 99 50       161 $in_pod = /^=(?!cut)/ ? 1 : /^=cut/ ? 0 : $in_pod;
    50          
77 99 100 66     356 next if $in_pod || /^\s*#/;
78              
79             # package NAMESPACE VERSION <-- we handle that
80             # package NAMESPACE VERSION BLOCK
81              
82 84 100 100     302 next unless /
83             (?
84             [\$*]
85             )
86             (?
87             (?
88             [\w\:\']*
89             )
90             \b
91             VERSION
92             )
93             \b
94             .*?
95             \=
96             (?
97             .*
98             )
99             /x ||
100             m/
101             \b package \s+
102             (? \w[\w\:\']* ) \s+
103             (? \S+ ) \s* [;{]
104             /x;
105 2     2   872 ( $sigil, $var, $rhs ) = @+{ qw(sigil var rhs) };
  2         1459  
  2         487  
  8         88  
106              
107 8 100       26 if ($sigil) {
108 4         24 $version = $class->_eval_version( $_, @+{ qw(sigil var rhs) } );
109             }
110             else {
111 4         20 $version = $class->_eval_version( $_, '$', 'VERSION', qq('$rhs') );
112             }
113              
114 8         712 last;
115             }
116 8 50 66     49 $line_number = undef if eof($fh) && ! defined( $version );
117 8         121 close $fh;
118              
119             return wantarray ?
120 8 50       127 ( $sigil, $var, $version, $file, $line_number )
121             :
122             $version;
123             }
124              
125             sub _eval_version {
126 8     8   30 my( $class, $line, $sigil, $var, $rhs ) = @_;
127              
128 8         499 require Safe;
129 8         31411 require version;
130 8         1495 local $^W = 0;
131              
132 8         32 my $s = Safe->new;
133 8         8658 $s->share_from('main', ['*version::']);
134 8         664 $s->share_from('version', ['&qv']);
135 8 50       329 if (defined $Devel::Cover::VERSION) {
136 8         22 $s->share_from('main', ['&Devel::Cover::use_file']);
137             }
138 8         343 $s->reval('$VERSION = ' . $rhs);
139 8         4851 my $version = $s->reval('$VERSION');
140              
141 8         3510 return $version;
142             }
143              
144             =back
145              
146             =head1 SOURCE AVAILABILITY
147              
148             This code is in Github:
149              
150             https://github.com/briandfoy/module-extract-version.git
151              
152             =head1 AUTHOR
153              
154             brian d foy, C<< >>
155              
156             I stole the some of this code from C in the PAUSE
157             code by Andreas König, but I've moved most of it around.
158              
159             Andrey Starodubtsev added code to handle the v5.12 and v5.14
160             C syntax.
161              
162             =head1 COPYRIGHT AND LICENSE
163              
164             Copyright © 2008-2022, brian d foy C<< >>. All rights reserved.
165              
166             You may redistribute this under the Artistic License 2.0.
167              
168             =cut
169              
170             1;