How to access the original monkeypatched method method in Perl?

I am trying to patch the monkey Perl class: I want to change the behavior of an existing method.

This perlmonks node shows how to add a function to an existing class. I found that this template can also be used to provide a new implementation of an existing function.

However, I would like to know how to call the original function.

I am looking for something like this:

use ExistingClass; # TODO: Somehow rename existingFunction() to oldExistingFunction(). sub ExistingClass::existingFunction { my $self = shift; # New behavior goes here. $self->oldExistingFunction(@_); # Call old behavior. # More new behavior here. } 
+4
source share
7 answers

Purpose Typeglob

 *ExistingClass::oldExistingFunction = *ExistingClass::existingFunction; 

Quick and dirty. This alias passes all existingFunction characters to oldExistingFunction . This includes the sub you are interested in, but also any scalars, arrays, hashes, descriptors that may have the same name.

  • Advantages: no thinking, it just works. "Quick"
  • Minuses: "dirty"

Purpose Coderef

 *ExistingClass::oldExistingFunction = \&ExistingClass::existingFunction; # or something using *ExistingClass::symbol{CODE} 

This is only an alias. It still runs in the package, so the oldExistingFunction symbol oldExistingFunction displayed globally, which may or may not be what you want. Probably not.

  • Advantages: these aliases do not "leak" to other types of variables.
  • Disadvantages: more thinking, more typing. Thinks a lot if you are going to use the syntax * ... {CODE} (I personally do not use it every day)

Lexical coderef

 my $oldFunction = \&ExistingClass::existingFunction; 

Using my contains a link to an old function that is visible only to the currrent block / file. There is no way that external code can get it without your help anymore. Note the calling convention:

 $self->$oldFunction(@args); $oldFunction->($self, @args); 
  • Advantages: no problems with visibility.
  • Disadvantages: it is more difficult to get the right.

Moose

See jrockway answer . This should be the β€œRight Way” because there are no more nuts with globes and / or links, but I don't know if this is enough to explain this.

+10
source

You must use Moose or Class :: Method :: Modifiers .

In this case, you can simply say:

 around 'some_method' => sub { my ($orig, $self, @args) = @_; # ... before original ... $self->$orig(@_); # ... after original ... }; 
+8
source

Among other answers, look at modules such as:

I will also talk about this in the chapter "Dynamic Languages" in Mastering Perl .

+4
source

Memoize is a good example of this.

+2
source

Just copy it into the lexical variable and name it.

 my $existing_function_ref = \&ExistingClass::existingFunction; *ExistingClass::existingFunction = sub { my $self = shift; $self->go_and_do_some_stuff(); my @returns = $existing_function_ref->( $self, @_ ); $self->do_some_stuff_with_returns( @returns ); return wantarray ? @returns : shift @returns; }; 

If you feel better with the OO syntax, you can create the UNIVERSAL::apply method (or in any base class you choose).

 sub UNIVERSAL::apply { my ( $self, $block ) = splice( @_, 0, 2 ); unshift @_, $self; goto &$block; } 

So you can call it like this:

 my @returns = $self->apply( $existing_function_ref, @_ ); 
+2
source

For Moose classes, you can just do what jrockway says ; for classes other than Moose, do the following:

 use Class::MOP (); use ExistingClass; Class::MOP::Class->initialize('ExistingClass')->add_around_method_modifier( existingFunction => sub { my $orig = shift; # new behaviour goes here # call old behaviour my $result = $orig->(@_); # more new behaviour goes here } ); 
+1
source

As an alternative, what's wrong:

 package NewClass; use base qw/ExistingClass/; sub existingFunction { # .... } sub oldExistingFunction { my $self = shift; return $self->SUPER::existingFunction(@_); } 
-1
source

All Articles