package Test::LatestPrereqs::ModuleInstall;
use strict;
use warnings;
use Carp;
use File::Spec;
use Config;
use File::Find::Rule;
use Class::Inspector;
my %ignorable_mi_methods = map { $_ => 1 } qw(
autoload call import new load load_extensions
preload find_extensions AUTOLOAD DESTROY
);
sub parse {
my ($class, $file) = @_;
my @requires;
no warnings 'redefine';
local $INC{'inc/Module/Install.pm'} = 1;
local $INC{'Module/Install/Base.pm'} = 1;
local $inc::Module::Install::VERSION = '666'; # cheat version check
local *inc::Module::Install::AUTOLOAD = sub { 1 };
local @inc::Module::Install::EXPORT = _get_methods();
local @inc::Module::Install::ISA = 'Exporter';
local *inc::Module::Install::requires = sub {
my %deps = (@_ == 1 ? ( $_[0] => 0 ) : @_);
push @requires, [ $_, $deps{$_} || 0 ] for keys %deps;
};
local *inc::Module::Install::build_requires = sub {
my %deps = (@_ == 1 ? ( $_[0] => 0 ) : @_);
push @requires, [ $_, $deps{$_} || 0 ] for keys %deps;
};
local *inc::Module::Install::test_requires = sub {
my %deps = (@_ == 1 ? ( $_[0] => 0 ) : @_);
push @requires, [ $_, $deps{$_} || 0 ] for keys %deps;
};
local *inc::Module::Install::recommends = sub {
my %deps = (@_ == 1 ? ( $_[0] => 0 ) : @_);
push @requires, [ $_, $deps{$_} || 0 ] for keys %deps;
};
local *inc::Module::Install::feature = sub {
my $name = shift;
while ( @_ ) {
my $key = shift;
if ( $key =~ /^\-/ ) { shift; next } # option
if ( $key && !ref $key ) {
push @requires, [ $key, shift || 0 ];
}
}
};
local *inc::Module::Install::features = sub {
my %features = @_;
while ( my ($name, $arrayref) = each %features ) {
inc::Module::Install::feature( $name, @$arrayref );
}
};
local *inc::Module::Install::include_deps = *inc::Module::Install::requires;
local *inc::Module::Install::Makefile = sub { 'Test::LatestPrereqs::ModuleInstall::Fake' };
local *inc::Module::Install::Meta = sub { 'Test::LatestPrereqs::ModuleInstall::Fake' };
eval {
package main;
no strict;
no warnings;
local *CORE::GLOBAL::exit = sub {};
require "$file";
};
delete $INC{$file};
if ($@ && $@ !~ /did not return a true value/) {
croak "Makefile.PL error: $@";
}
return @requires;
}
sub _get_methods {
my $dir = 'inc/Module/Install';
unless (-d $dir) {
$dir = File::Spec->catdir( $Config{sitelib}, 'Module/Install' );
$dir =~ s{\\}{/}g;
}
my @methods;
foreach my $file ( File::Find::Rule->file->name('*.pm')->in($dir) ) {
eval {
require File::Spec->rel2abs($file);
my %seen;
@methods = grep { !$seen{$_}++ && !$ignorable_mi_methods{$_} }
@methods,
@{ Class::Inspector->methods( _file_to_mod( $file ), 'public' ) };
delete $INC{$file};
};
warn "inspecting error: $@" if $@;
}
return @methods;
}
sub _file_to_mod {
my $file = shift;
$file =~ s{\\}{/}g;
$file =~ s{^.+/Module/Install}{Module/Install};
$file =~ s{/}{::}g;
$file =~ s{\.pm}{};
$file;
}
package #
Test::LatestPrereqs::ModuleInstall::Fake;
sub write {}
1;
__END__
=head1 NAME
Test::LatestPrereqs::ModuleInstall
=head1 SYNOPSIS
my @requires = Test::LatestPrereqs::ModuleInstall->parse($makefile_pl);
=head1 DESCRIPTION
This is used internally to parse Makefile.PL (with L<Module::Install>) to get requirements.
=head1 METHODS
=head2 parse
parses Makefile.PL and returns a list of requirements.
=head1 AUTHOR
Kenichi Ishigaki, E<lt>ishigaki@cpan.orgE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2009 by Kenichi Ishigaki.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=cut