How can I monkey-patch an instance method in Perl?

前端 未结 8 2308
醉酒成梦
醉酒成梦 2020-12-08 01:25

I\'m trying to monkey-patch (duck-punch :-) a LWP::UserAgent instance, like so:

sub _user_agent_get_basic_credentials_patch {
  return ($usernam         


        
8条回答
  •  情深已故
    2020-12-08 01:57

    Building upon John Siracusa's answer… I found that I still wanted a reference to the original function. So I did this:

    MONKEY_PATCH_INSTANCE:
    {
      my $counter = 1; # could use a state var in perl 5.10
    
      sub monkey_patch_instance
      {
        my($instance, $method, $code) = @_;
        my $package = ref($instance) . '::MonkeyPatch' . $counter++;
        no strict 'refs';
        my $oldFunction = \&{ref($instance).'::'.$method};
        @{$package . '::ISA'} = (ref($instance));
        *{$package . '::' . $method} = sub {
            my ($self, @args) = @_;
            $code->($self, $oldFunction, @args);
        };
        bless $_[0], $package; # sneaky re-bless of aliased argument
      }
    }
    
    # let's say you have a database handle, $dbh
    # but you want to add code before and after $dbh->prepare("SELECT 1");
    
    monkey_patch_instance($dbh, prepare => sub {
        my ($self, $oldFunction, @args) = @_;
    
        print "Monkey patch (before)\n";
        my $output = $oldFunction->(($self, @args));
        print "Monkey patch (after)\n";
    
        return $output;
        });
    

    It's the same as in the original answer, except I pass through some parameters $self and $oldFunction.

    This lets us invoke $self's $oldFunction as usual, but decorate additional code around it.

提交回复
热议问题