ハックがあるため必要とされるrequire(従って、use戻る前に両方のコンパイルおよび実行するモジュール)。
同じことが当てはまりますeval。eval実行せずにコードをコンパイルするために使用することはできません。
私が見つけた最も邪魔にならない解決策は、オーバーライドすることDB::postponedです。これは、コンパイル済みの必要なファイルを評価する前に呼び出されます。残念ながら、これはデバッグ時にのみ呼び出されperl -dます()。
別の解決策は、ファイルを読み取って変更し、変更されたファイルを評価することです。
use File::Slurper qw( read_binary );
eval(read_binary("Foo.pm") . <<'__EOS__') or die $@;
package Foo {
no warnings qw( redefine );
sub bar { 7 }
}
__EOS__
上記は適切に設定%INCされておらず、警告などで使用されているファイル名をめちゃくちゃにしている、呼び出していないDB::postponedなどです。以下はより堅牢なソリューションです。
use IO::Unread qw( unread );
use Path::Class qw( dir );
BEGIN {
my $preamble = '
UNITCHECK {
no warnings qw( redefine );
*Foo::bar = sub { 7 };
}
';
my @libs = @INC;
unshift @INC, sub {
my (undef, $fn) = @_;
return undef if $_[1] ne 'Foo.pm';
for my $qfn (map dir($_)->file($fn), @libs) {
open(my $fh, '<', $qfn)
or do {
next if $!{ENOENT};
die $!;
};
unread $fh, "$preamble\n#line 1 $qfn\n";
return $fh;
}
return undef;
};
}
use Foo;
私が使用UNITCHECK私がオーバーライドを先頭に追加するので(使用して(コンパイル後が、実行前に呼び出される)unread)ではなく、全体のファイルの読み込みと新しい定義を追加します。そのアプローチを使用したい場合は、使用して返すファイルハンドルを取得できます。
open(my $fh_for_perl, '<', \$modified_code);
return $fh_for_perl;
@INCフックについて言及している@Grinnzへの称賛。
Foo::barが、use Fooはコンパイル段階(以前に何か定義されていた場合はバーを再定義)とFooのランタイム段階の両方を実行します。私が考えられる唯一のこと@INCは、Fooのロード方法を変更するための非常にハックなフックです。