Reputation: 3131
This example works fine:
use File::Slurp qw(read_file);
local *File::Slurp::read_file = sub {
return 'test';
};
warn File::Slurp::read_file('/root/test.txt'); # return 'test'
this one too:
use File::Slurp qw(read_file);
local *read_file = sub {
return 'test';
};
warn read_file('/root/test.txt'); # return 'test'
but if I use full name of function in typeglob it doesn't work and attempt to read file:
use File::Slurp qw(read_file);
local *File::Slurp::read_file = sub {
return 'test';
};
warn read_file('/root/test.txt');
Could anyone explain why I can not redefine subroutine by full namespace, File::Slurp::read_file
, and use by short name?
In case of object method, it works fine:
use LWP::UserAgent;
local *LWP::UserAgent::get = sub {
return HTTP::Response->new( undef, undef, undef, 'Hello world' );
};
my $ua = LWP::UserAgent->new;
warn $ua->get()->content;
Upvotes: 5
Views: 352
Reputation: 66924
When a sub is exported its reference is written to the caller's symbol table. Then after the sub is redefined in the module the unqualified name in the caller still refers to the "old" one, that was Exported, and not the redefined one.
One clear fix is to explicitly alias the (unqualified) name in the calling package
*func = *{ Module::func } = sub { ... };
Then wrap this in a subroutine, from which all wanted namespaces can be taken care of
sub redefine_sub {
my ($fqn, $code) = @_;
no warnings 'redefine'; # these pragmas are lexical, and
no strict 'refs'; # so stay scoped to this sub only
*{ $fqn } = $code;
# Redefine in caller
my ($name) = $fqn =~ /.*::(.*)/;
my $to_caller = caller() . '::' . $name;
*{ $to_caller } = $code;
}
In the caller
use Module qw(func);
redefine_sub('Module::func', sub { ... });
(Original attempts, that didn't work well, have been removed)
Upvotes: 2
Reputation: 4013
Your problem is caused by how the way export works. and how Perl assigns names to values. In Perl each name is a link to a value so sub read_line { ... }
creates an anonymous subroutine reference and assigns it to the name &read_line
use File::Slurp qw(read_file);
local *File::Slurp::read_file = sub {
return 'test';
};
In your first example you are overriding File::Slurp::read_file
and then calling File::Slurp::read_file
so you get your version of File::Slurp::read_file
.
use File::Slurp qw(read_file);
local *read_file = sub {
return 'test';
};
In your second example you are overriding your imported version of read_file
and then calling that so you get your version of read_file
use File::Slurp qw(read_file);
local *File::Slurp::read_file = sub {
return 'test';
};
In your third example the following happens:
use File::Slurp;
does a *read_file = \&File::Slurp::read_file
at compile time, which makes read_file
point to the existing version of File::Slurp::read_file
. Your code then assigns *File::Slurp::read_file
a new sub ref, however this does not change read_file
and it still points to the sub ref that File::Slurp::read_file
originally pointed to. You then call read_file
which is pointing to the original imported version of File::Slurp::read_file
In your fourth example Perl's method resolution system means that you are calling LWP::UserAgent::get
so this is equivalent to your first example.
Upvotes: 7