एक हैक की आवश्यकता होती है क्योंकि 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
दोनों संकलन चरण (यदि कुछ पहले से परिभाषित किया गया था तो फिर से परिभाषित करना) और फू के रनटाइम चरण दोनों को चलाएंगे। केवल एक चीज जिसके बारे में मैं सोच सकता हूं@INC
कि फू लोड होने के तरीके को संशोधित करने के लिए एक गहरी हैकिंग हुक होगी।