ต้องการแฮ็กเพราะ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;
รุ่งโรจน์ถึง @Grinnz สำหรับการพูดถึง@INC
hooks
Foo::bar
แต่use Foo
จะเรียกใช้ทั้งขั้นตอนการคอมไพล์ (กำหนดบาร์ใหม่หากมีสิ่งใดกำหนดไว้ก่อนหน้านี้) และเฟสรันไทม์ของ Foo สิ่งเดียวที่ฉันนึกได้ก็คือ@INC
ตะขอที่แฮ็คอย่างลึกล้ำเพื่อปรับเปลี่ยนวิธีโหลดของฟู