$VERSION
=
'0.2808_05'
;
$VERSION
=
eval
$VERSION
;
my
$PKG_REGEXP
=
qr{ # match a package declaration
^[\s\{;]* # intro chars on a line
package # the word 'package'
\s+ # whitespace
([\w:]+) # a package name
\s* # optional whitespace
; # semicolon line terminator
}
x;
my
$VARNAME_REGEXP
=
qr{ # match fully-qualified VERSION name
([\$*]) # sigil - $ or *
(
( # optional leading package name
(?:::|\')? # possibly starting like just :: (ala $::VERSION)
(?:\w+(?:::|\'))* # Foo::Bar:: ...
)?
VERSION
)\b
}
x;
my
$VERS_REGEXP
=
qr{ # match a VERSION definition
(?:
\(\s*$VARNAME_REGEXP\s*\) # with parens
|
$VARNAME_REGEXP # without parens
)
\s*
=[^=~] # = but not ==, nor =~
}
x;
sub
new_from_file {
my
$class
=
shift
;
my
$filename
= File::Spec->rel2abs(
shift
);
return
undef
unless
defined
(
$filename
) && -f
$filename
;
return
$class
->_init(
undef
,
$filename
,
@_
);
}
sub
new_from_module {
my
$class
=
shift
;
my
$module
=
shift
;
my
%props
=
@_
;
$props
{inc} ||= \
@INC
;
my
$filename
=
$class
->find_module_by_name(
$module
,
$props
{inc} );
return
undef
unless
defined
(
$filename
) && -f
$filename
;
return
$class
->_init(
$module
,
$filename
,
%props
);
}
sub
_init {
my
$class
=
shift
;
my
$module
=
shift
;
my
$filename
=
shift
;
my
%props
=
@_
;
my
(
%valid_props
,
@valid_props
);
@valid_props
=
qw( collect_pod inc )
;
@valid_props
{
@valid_props
} =
delete
(
@props
{
@valid_props
} );
warn
"Unknown properties: @{[keys %props]}\n"
if
scalar
(
%props
);
my
%data
= (
module
=>
$module
,
filename
=>
$filename
,
version
=>
undef
,
packages
=> [],
versions
=> {},
pod
=> {},
pod_headings
=> [],
collect_pod
=> 0,
%valid_props
,
);
my
$self
=
bless
(\
%data
,
$class
);
$self
->_parse_file();
unless
(
$self
->{module} and
length
(
$self
->{module})) {
my
(
$v
,
$d
,
$f
) = File::Spec->splitpath(
$self
->{filename});
if
(
$f
=~ /\.pm$/) {
$f
=~ s/\..+$//;
my
@candidates
=
grep
/
$f
$/, @{
$self
->{packages}};
$self
->{module} =
shift
(
@candidates
);
}
else
{
if
(
grep
/main/, @{
$self
->{packages}}) {
$self
->{module} =
'main'
;
}
else
{
$self
->{module} =
$self
->{packages}[0] ||
''
;
}
}
}
$self
->{version} =
$self
->{versions}{
$self
->{module}}
if
defined
(
$self
->{module} );
return
$self
;
}
sub
_do_find_module {
my
$class
=
shift
;
my
$module
=
shift
||
die
'find_module_by_name() requires a package name'
;
my
$dirs
=
shift
|| \
@INC
;
my
$file
= File::Spec->catfile(
split
( /::/,
$module
));
foreach
my
$dir
(
@$dirs
) {
my
$testfile
= File::Spec->catfile(
$dir
,
$file
);
return
[ File::Spec->rel2abs(
$testfile
),
$dir
]
if
-e
$testfile
and !-d _;
return
[ File::Spec->rel2abs(
"$testfile.pm"
),
$dir
]
if
-e
"$testfile.pm"
;
}
return
;
}
sub
find_module_by_name {
my
$found
=
shift
()->_do_find_module(
@_
) or
return
;
return
$found
->[0];
}
sub
find_module_dir_by_name {
my
$found
=
shift
()->_do_find_module(
@_
) or
return
;
return
$found
->[1];
}
sub
_parse_version_expression {
my
$self
=
shift
;
my
$line
=
shift
;
my
(
$sig
,
$var
,
$pkg
);
if
(
$line
=~
$VERS_REGEXP
) {
(
$sig
,
$var
,
$pkg
) = $2 ? ( $1, $2, $3 ) : ( $4, $5, $6 );
if
(
$pkg
) {
$pkg
= (
$pkg
eq
'::'
) ?
'main'
:
$pkg
;
$pkg
=~ s/::$//;
}
}
return
(
$sig
,
$var
,
$pkg
);
}
sub
_parse_file {
my
$self
=
shift
;
my
$filename
=
$self
->{filename};
my
$fh
= IO::File->new(
$filename
)
or
die
(
"Can't open '$filename': $!"
);
$self
->_parse_fh(
$fh
);
}
sub
_parse_fh {
my
(
$self
,
$fh
) =
@_
;
my
(
$in_pod
,
$seen_end
,
$need_vers
) = ( 0, 0, 0 );
my
(
@pkgs
,
%vers
,
%pod
,
@pod
);
my
$pkg
=
'main'
;
my
$pod_sect
=
''
;
my
$pod_data
=
''
;
while
(
defined
(
my
$line
= <
$fh
> )) {
my
$line_num
= $.;
chomp
(
$line
);
next
if
$line
=~ /^\s*
$in_pod
= (
$line
=~ /^=(?!cut)/) ? 1 : (
$line
=~ /^=cut/) ? 0 :
$in_pod
;
last
if
!
$in_pod
&&
$line
=~ /^__(?:DATA|END)__$/;
if
(
$in_pod
||
$line
=~ /^=cut/ ) {
if
(
$line
=~ /^=head\d\s+(.+)\s*$/ ) {
push
(
@pod
, $1 );
if
(
$self
->{collect_pod} &&
length
(
$pod_data
) ) {
$pod
{
$pod_sect
} =
$pod_data
;
$pod_data
=
''
;
}
$pod_sect
= $1;
}
elsif
(
$self
->{collect_pod} ) {
$pod_data
.=
"$line\n"
;
}
}
else
{
$pod_sect
=
''
;
$pod_data
=
''
;
my
(
$vers_sig
,
$vers_fullname
,
$vers_pkg
) =
$self
->_parse_version_expression(
$line
);
if
(
$line
=~
$PKG_REGEXP
) {
$pkg
= $1;
push
(
@pkgs
,
$pkg
)
unless
grep
(
$pkg
eq
$_
,
@pkgs
);
$vers
{
$pkg
} =
undef
unless
exists
(
$vers
{
$pkg
} );
$need_vers
= 1;
}
elsif
(
$vers_fullname
&&
$vers_pkg
) {
push
(
@pkgs
,
$vers_pkg
)
unless
grep
(
$vers_pkg
eq
$_
,
@pkgs
);
$need_vers
= 0
if
$vers_pkg
eq
$pkg
;
unless
(
defined
$vers
{
$vers_pkg
} &&
length
$vers
{
$vers_pkg
} ) {
$vers
{
$vers_pkg
} =
$self
->_evaluate_version_line(
$vers_sig
,
$vers_fullname
,
$line
);
}
else
{
warn
<<"EOM" unless $line =~ /=\s*eval/;
Package '$vers_pkg' already declared with version '$vers{$vers_pkg}',
ignoring subsequent declaration on line $line_num.
EOM
}
}
elsif
( !
exists
(
$vers
{main}) &&
$pkg
eq
'main'
&&
$vers_fullname
) {
$need_vers
= 0;
my
$v
=
$self
->_evaluate_version_line(
$vers_sig
,
$vers_fullname
,
$line
);
$vers
{
$pkg
} =
$v
;
push
(
@pkgs
,
'main'
);
}
elsif
( !
exists
(
$vers
{main}) &&
$pkg
eq
'main'
&&
$line
=~ /\w+/ ) {
$need_vers
= 1;
$vers
{main} =
''
;
push
(
@pkgs
,
'main'
);
}
elsif
(
$vers_fullname
&&
$need_vers
) {
$need_vers
= 0;
my
$v
=
$self
->_evaluate_version_line(
$vers_sig
,
$vers_fullname
,
$line
);
unless
(
defined
$vers
{
$pkg
} &&
length
$vers
{
$pkg
} ) {
$vers
{
$pkg
} =
$v
;
}
else
{
warn
<<"EOM";
Package '$pkg' already declared with version '$vers{$pkg}'
ignoring new version '$v' on line $line_num.
EOM
}
}
}
}
if
(
$self
->{collect_pod} &&
length
(
$pod_data
) ) {
$pod
{
$pod_sect
} =
$pod_data
;
}
$self
->{versions} = \
%vers
;
$self
->{packages} = \
@pkgs
;
$self
->{pod} = \
%pod
;
$self
->{pod_headings} = \
@pod
;
}
{
my
$pn
= 0;
sub
_evaluate_version_line {
my
$self
=
shift
;
my
(
$sigil
,
$var
,
$line
) =
@_
;
my
$vsub
;
$pn
++;
my
$eval
=
qq{BEGIN { q# Hide from _packages_inside()
#; package Module::Build::ModuleInfo::_version::p$pn;
use Module::Build::Version;
no strict;
local $sigil$var;
\$$var=undef;
\$vsub = sub {
$line;
\$$var
}
;
}};
local
$^W;
eval
$eval
;
warn
"Error evaling version line '$eval' in $self->{filename}: $@\n"
if
$@;
(
ref
(
$vsub
) eq
'CODE'
) or
die
"failed to build version sub for $self->{filename}"
;
my
$result
=
eval
{
$vsub
->() };
die
"Could not get version from $self->{filename} by executing:\n$eval\n\nThe fatal error was: $@\n"
if
$@;
$result
= Module::Build::Version->new(
$result
);
return
$result
;
}
}
sub
name {
$_
[0]->{module} }
sub
filename {
$_
[0]->{filename} }
sub
packages_inside { @{
$_
[0]->{packages}} }
sub
pod_inside { @{
$_
[0]->{pod_headings}} }
sub
contains_pod { $
sub
version {
my
$self
=
shift
;
my
$mod
=
shift
||
$self
->{module};
my
$vers
;
if
(
defined
(
$mod
) &&
length
(
$mod
) &&
exists
(
$self
->{versions}{
$mod
} ) ) {
return
$self
->{versions}{
$mod
};
}
else
{
return
undef
;
}
}
sub
pod {
my
$self
=
shift
;
my
$sect
=
shift
;
if
(
defined
(
$sect
) &&
length
(
$sect
) &&
exists
(
$self
->{pod}{
$sect
} ) ) {
return
$self
->{pod}{
$sect
};
}
else
{
return
undef
;
}
}
1;