Как вы заменяете метод объекта Moose во время выполнения? - PullRequest
6 голосов
/ 12 марта 2010

Можно ли заменить метод объекта Moose во время выполнения? Посмотрев на исходный код Class::MOP::Method (который Moose::Meta::Method наследует от) я пришел к выводу, что, выполнив

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

Я мог бы заменить во время выполнения метод объекта. Я могу получить метод, используя

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

Однако это не совсем сработало.

Можно ли изменить методы во время выполнения? И как это сделать с помощью Moose?

Ответы [ 3 ]

4 голосов
/ 12 марта 2010

Идея Синана - прекрасное начало.

Но с небольшой дополнительной настройкой вы можете сделать это с помощью метода доступа к методу, как при использовании обычного метода.

#!/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;
    }

}

Два метода в Frob очень похожи.

  • frobit передает все аргументы, включая инвокант к коду ref.
  • goto_frob передает все аргументы, включая инвокант в код ref, и заменяет кадр стека goto_frob на код refs.

Что использовать, зависит от того, что вы хотите в стеке.


Относительно хранения тела объекта Class::MOP::Method, вот так $method->{body} = sub { 'foo' }:

Никогда не стоит нарушать инкапсуляцию, когда вы выполняете ООП. Особенно, если вы работаете со сложными объектными системами, такими как Moose и Class :: MOP. Это напрашивается на неприятности. Иногда нет другого способа получить то, что вы хотите, но даже тогда нарушать инкапсуляцию - все еще плохая идея.

4 голосов
/ 12 марта 2010

Лось или нет, это не похоже на хорошую идею.

Вместо этого спроектируйте свой объект, чтобы иметь метод доступа для метода. Например, пользователи вашего класса могут использовать My::Frobnicator->frobnicator->() для получения и вызова метода frobnicator и использовать My::Frobnicator->frobnicator(sub { } ) для его установки.

3 голосов
/ 12 марта 2010

Используя ранее , упомянутый MooseX::SingletonMethod, вы можете заменить метод объектов.

Например:

{
    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

Также см. Этот SO-ответ на Что мне делать с объектом, который больше не должен использоваться в Perl? , который показывает, как этого можно добиться с помощью ролей Moose.

/ I3az /

...