开发者

How do you replace a method of a Moose object at runtime?

Is it possible to replace a method of a Moose object at runtime ? By looking at the source code of Class::MOP::Method (which Moose::Meta::Method inherits from) I concluded that by doing

 $method->{body} = sub{ my stuff }

I would be开发者_StackOverflow社区 able to replace at runtime a method of an object. I can get the method using

 $object->meta->find_method_by_name(<method_name>);

However, this didn't quite work out.

Is it conceivable to modify methods at run time? And, what is the way to do it with Moose?


Moose or not, that does not sound like a good idea.

Instead, design your object to have an accessor for the method. For example, users of your class can use My::Frobnicator->frobnicator->() to get and invoke the frobnicator method and use My::Frobnicator->frobnicator(sub { } ) to set it.


Sinan's idea is a great start.

But with an little extra tweak, you can make using your method accessor just like using a normal method.

#!/usr/bin/perl
use strict;
use warnings;
use Carp;

my $f = Frob->new;

$f->frob(
    sub { 
        my $self = shift;
        print "$self was frobbed\n"; 
        print Carp::longmess('frob') 
    }
);

print "\nCall frob as normal sub\n";
$f->frobit;

print "\nGoto frob\n";
$f->goto_frob;

BEGIN { 
    package Frob;
    use Moose;

    has 'frob' => (
        is => 'rw',
        isa => 'CodeRef',
    );

    sub frobit {
        &{$_[0]->frob};
    }
    sub goto_frob {
        goto $_[0]->frob;
    }

}

The two methods in Frob are very similar.

  • frobit passes all arguments, including the invocant to the code ref.
  • goto_frob passes all arguments, including the invocant to the code ref, and replaces goto_frob's stack frame with the code refs.

Which to use depends on what you want in the stack.


Regarding munging the body storage of a Class::MOP::Method object, like so $method->{body} = sub { 'foo' }:

It's never a good idea to violate encapsulation when you are doing OOP. Especially not when you are working with complex object systems like Moose and Class::MOP. It's asking for trouble. Sometimes, there is no other way to get what you want, but even then, violating encapsulation is still a bad idea.


Using the previously mentioned MooseX::SingletonMethod you can replace an objects method.

For example:

{
    package Foo;
    use MooseX::SingletonMethod;
    sub foo { say 'bar' };
}

my $bar = Foo->new;
my $baz = Foo->new;

# replace foo method just in $baz object
$baz->add_singleton_method( foo => sub { say 'baz' } );

$bar->foo;     # => bar
$baz->foo;     # => baz

Also see this SO answer to What should I do with an object that should no longer be used in Perl?, which shows how this can be achieved using Moose roles.

/I3az/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜