Bir kesmek gereklidir çünkü require
(ve böylece use
) her iki derlenir ve yürütür modülü dönmeden önce.
Aynı şey geçerli eval
. eval
kodu yürütmeden de derlemek için kullanılamaz.
Bulduğum en az müdahaleci çözüm geçersiz kılmak olurdu DB::postponed
. Bu derlenmiş gerekli bir dosyayı değerlendirmeden önce çağrılır. Ne yazık ki, yalnızca hata ayıklama ( perl -d
) sırasında çağrılır .
Başka bir çözüm, dosyayı okumak, değiştirmek ve değiştirilmiş dosyayı değerlendirmek olabilir, örneğin aşağıdakiler gibi:
use File::Slurper qw( read_binary );
eval(read_binary("Foo.pm") . <<'__EOS__') or die $@;
package Foo {
no warnings qw( redefine );
sub bar { 7 }
}
__EOS__
Yukarıdakiler düzgün ayarlanmamıştır %INC
, uyarılar tarafından kullanılan dosya adını karıştırır ve böyle çağırmaz DB::postponed
, vb. Aşağıdakiler daha sağlam bir çözümdür:
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;
Ben kullandım UNITCHECK
(derleme sonra ama yürütmeden önce denir) çünkü unread
tüm dosyayı okumak ve yeni tanım eklemek yerine geçersiz kılma (kullanarak ) önermiş. Bu yaklaşımı kullanmak istiyorsanız, kullanarak geri dönmek için bir dosya tanıtıcısı alabilirsiniz
open(my $fh_for_perl, '<', \$modified_code);
return $fh_for_perl;
Horoz bahsettiği için @Grinnz için Kudos @INC
.
Foo::bar
, ancakuse Foo
hem derleme aşamasını (daha önce tanımlanmış bir şey varsa yeniden tanımlama çubuğu) hem de Foo'nun çalışma zamanı aşamasını çalıştıracaktır. Aklıma gelen tek şey,@INC
Foo'nun nasıl yüklendiğini değiştirmek için derin bir çengel kanca olurdu .