Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redefine perl function using typeglob doesn't work as expected

Tags:

perl

typeglob

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;
like image 333
Paul Serikov Avatar asked Mar 05 '23 17:03

Paul Serikov


1 Answers

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.

like image 68
JGNI Avatar answered Mar 15 '23 22:03

JGNI