Есть ли способ использовать Moose :: Exporter из объекта Moose? - PullRequest
3 голосов
/ 02 декабря 2009

Я ищу способ настроить некоторые вспомогательные методы из родительского Moose класса, а не автономного служебного класса. Если это возможно, это будет более прозрачный способ добавления Moose sugar в модули, так как он не требует явного указания каких-либо вспомогательных модулей (как все будет происходить через объявление extends).

Основываясь на примере , приведенном в документации , это примерно то, к чему я стремлюсь:

package Parent;

use Moose;

Moose::Exporter->setup_import_methods(
    with_meta => [ 'has_rw' ],
    as_is     => [ 'thing' ],
    also      => 'Moose',
);

sub has_rw {
    my ( $meta, $name, %options ) = @_;
    $meta->add_attribute(
        $name,
        is => 'rw',
        %options,
    );
}

# then later ...
package Child;

use Moose;
extends 'Parent';

has 'name';
has_rw 'size';
thing;

Однако это не работает:

perl -I. -MChild -wle'$obj = Child->new(size => 1); print $obj->size'
String found where operator expected at Child.pm line 10, near "has_rw 'size'"
        (Do you need to predeclare has_rw?)
syntax error at Child.pm line 10, near "has_rw 'size'"
Bareword "thing" not allowed while "strict subs" in use at Child.pm line 12.
Compilation failed in require.
BEGIN failed--compilation aborted.

PS. Я также пытался переместить магию экспорта в роль (with Role; вместо extends Parent;), но происходят те же ошибки.

1 Ответ

7 голосов
/ 02 декабря 2009

Это не поддерживается, и для этого есть веская причина. Класс или роль не совпадают с сахарными методами, и на каком-то уровне разные вещи должны отличаться. Если ваша проблема заключается в том, чтобы «использовать» пакет Moose + A Custom Sugar, то вы можете решить эту проблему, просто экспортировав свой собственный пакет Moose, украдя из вашего примера:

package MySugar;
use strict;
use Moose::Exporter;

Moose::Exporter->setup_import_methods(
    with_meta => [ 'has_rw' ],
    as_is     => [ 'thing' ],
    also      => 'Moose',
);

sub has_rw {
    my ( $meta, $name, %options ) = @_;
    $meta->add_attribute(
        $name,
        is => 'rw',
        %options,
    );
}

Тогда вы просто говорите:

package MyApp;
use MySugar; # imports everything from Moose + has_rw and thing    
extends(Parent);

has_rw 'name';
has 'size';
thing;

Так работает MooseX::POE, а также несколько других пакетов. Я бы, например, возразил против того, чтобы extends вводил сахар, как вы предлагаете здесь, потому что класс не является набором функций сахара, и эти два действительно никогда не следует путать.

ОБНОВЛЕНИЕ: чтобы объединить оба сразу, самый чистый подход состоит в том, чтобы переработать Parent как роль, которая применяется к Moose :: Object.

package Parent::Methods;
use 5.10.0;
use Moose::Role;

sub something_special { say 'sparkles' }

Затем мы просто изменим вызов Moose :: Exporter в MySugar, чтобы он выглядел как

Moose::Exporter->setup_import_methods(
    apply_base_class_roles => 'Parent::Methods',
    with_meta              => ['has_rw'],
    as_is                  => ['thing'],
    also                   => 'Moose',
);

Теперь вы можете просто сказать

package MyApp;
use MySugar; 

has_rw 'name';
has 'size';
thing;

package main;
MyApp->new->something_special; # prints sparkles

Который, я думаю, последняя деталь, которую вы хотели.

...