Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Re^2: How to redefine a modules private function?

by salva (Canon)
on Mar 09, 2022 at 10:03 UTC ( [id://11141934]=note: print w/replies, xml ) Need Help??


in reply to Re: How to redefine a modules private function?
in thread How to redefine a modules private function?

Well, and now, something that actually works:
#!/usr/bin/perl use strict; use warnings; use feature 'say'; use Path::Tiny; use File::Temp qw(tempfile); sub hotpatch { if ($_[1] eq 'AnyEvent/DNS.pm') { for my $inc (@INC) { next if ref $inc; my $fn = path($inc)->child($_[1]); if (open my $in, '<', $fn) { my ($out) = tempfile(UNLINK => 1); while (<$in>) { s/sub\s+DOMAIN_PORT\b/sub DOMAIN_PORT () { 1053 } +sub FORMER_DOMAIN_PORT/; print {$out} $_; } seek($out, 0, 0); return $out; } } warn "couldn't patch AnyEvent::DNS"; } return undef; } BEGIN { unshift @INC, \&hotpatch } use AnyEvent::DNS; BEGIN { @INC = grep not(ref and $_ eq \&hotpatch), @INC } say AnyEvent::DNS::DOMAIN_PORT(); say AnyEvent::DNS::FORMER_DOMAIN_PORT();

Replies are listed 'Best First'.
Re^3: How to redefine a modules private function?
by Corion (Patriarch) on Mar 09, 2022 at 10:08 UTC

    You can avoid hitting the disk (even though that's great for debugging) by using an in-memory file in your @INC hook:

    open my $out, \my $buffer or die "Couldn't patch AnyEvent::DNS; your Perl do +es not support in-memory filehandles"; while (<$in>) { s/sub\s+DOMAIN_PORT\b/sub DOMAIN_PORT () { 1053 } +sub FORMER_DOMAIN_PORT/; $buffer .= $_; } return $out;
      Ok, here it is the full solution using an in-memory file:
      use strict; use warnings; use Path::Tiny; sub hotpatch { my ($self, $module) = @_; if ($module eq 'AnyEvent/DNS.pm') { for my $inc (@INC) { next if ref $inc; if (open my $in, '<', path($inc)->child($module)) { my $buffer = do { undef $/; <$in> }; $buffer =~ s/\bsub\s+DOMAIN_PORT\b/sub DOMAIN_PORT () +{ 1053 } sub FORMER_DOMAIN_PORT/; open my $out, '<', \$buffer or die "Couldn't patch AnyEvent::DNS; your Perl do +es not support in-memory filehandles"; return $out; } } warn "couldn't patch AnyEvent::DNS"; } return undef; } BEGIN { unshift @INC, \&hotpatch } use AnyEvent::DNS; BEGIN { @INC = grep not(ref and $_ eq \&hotpatch), @INC } say AnyEvent::DNS::DOMAIN_PORT(); say AnyEvent::DNS::FORMER_DOMAIN_PORT();

        Nice! That's like a more concise version of what I posted here.

        Nice.

        But when used in production, I'd suggest to check if the regex was successful and raise an error otherwise.

        This is practically a source filter, and the patched source could change between versions. (like implementing a variable port)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11141934]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (5)
As of 2024-03-29 01:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found