Un hack est nécessaire car require
(et donc use
) à la fois compile et exécute le module avant de revenir.
Il en va de même eval
. eval
ne peut pas être utilisé pour compiler du code sans l'exécuter également.
La solution la moins intrusive que j'ai trouvée serait de passer outre DB::postponed
. Ceci est appelé avant d'évaluer un fichier requis compilé. Malheureusement, il n'est appelé que lors du débogage ( perl -d
).
Une autre solution serait de lire le fichier, de le modifier et d'évaluer le fichier modifié, un peu comme ce qui suit:
use File::Slurper qw( read_binary );
eval(read_binary("Foo.pm") . <<'__EOS__') or die $@;
package Foo {
no warnings qw( redefine );
sub bar { 7 }
}
__EOS__
Ce qui précède n'est pas correctement défini %INC
, il gâche le nom de fichier utilisé par les avertissements et autres, il n'appelle pas DB::postponed
, etc. La solution suivante est plus robuste:
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;
J'ai utilisé UNITCHECK
(qui est appelé après la compilation mais avant l'exécution) parce que j'ai ajouté le remplacement (à l'aide unread
) plutôt que de lire le fichier entier et d'ajouter la nouvelle définition. Si vous souhaitez utiliser cette approche, vous pouvez obtenir un descripteur de fichier à retourner en utilisant
open(my $fh_for_perl, '<', \$modified_code);
return $fh_for_perl;
Félicitations à @Grinnz pour avoir mentionné les @INC
crochets.
Foo::bar
, maisuse Foo
elle exécutera à la fois la phase de compilation (barre de redéfinition si quelque chose a déjà été définie là-bas) et la phase d'exécution de Foo. La seule chose à laquelle je peux penser serait un@INC
crochet profondément hacky pour modifier la façon dont Foo est chargé.