Как мне потребовать аргумент конструктора Moose, который не является атрибутом? - PullRequest
2 голосов
/ 26 октября 2010

У меня есть объектный модуль Moose, который должен принимать относительно большую структуру данных (ds) в качестве одного из аргументов своего конструктора. Он используется для вычисления некоторых атрибутов объекта. Тем не менее, я не хочу хранить ds сам в качестве атрибутов - он необходим только при построении объекта.

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

Как я могу обойти это?

Ответы [ 2 ]

3 голосов
/ 26 октября 2010

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

sub generate_foo_from_ds {
    my $class = shift; 
    my %arg = @_;

    my $ds = $arg{foo_data};

    # Get attributes from args
    my %attrib;
    for (qw(foo bar baz ) {
        croak "Attrib '$_' is required" unless exists $arg{$_};
        $attrib{$_} = $arg{$_};
    }

    # calculate some more attributes here.
    $attrib{griz} = $ds->{whee} * $ds->{whoosh} / $ds->{whiz}[12];

    my $foo = $class->new( %attrib );

    return $foo;
}

Тогда сделайте ваши объекты такими:

my $foo = Foo->generate_foo_from_ds( foo_data => $bar, foo => 1, bar => 2, baz => 2 );

Теперь вам не нужно беспокоиться о странных проблемах с сериализацией, BUILDARGS или даже BUILD. У вас есть простой метод, и это все.

2 голосов
/ 26 октября 2010

Вы можете использовать для этого либо BUILD, либо BUILDARGS. Трудно сказать, что было бы лучше, не зная больше о том, что вы пытаетесь сделать, но я бы предположил, что BUILD будет лучшим выбором.

sub BUILD {
    my $self = shift;
    my $args = shift;

    my $ds = $args->{ds} or confess "Argument (ds) is required";

    $self->some_attr($ds->{...});
    $self->other_attr($ds->{foo}[3]);
    ...
} # end BUILD

Если вы хотите, чтобы Moose проверил тип и удостоверился в его наличии, вы должны сделать его атрибутом. Но вы можете очистить его в методе BUILD после его использования.

 has 'ds' => (
     is       => 'ro',
     isa      => 'SomeType',
     required => 1,
     clearer  => '_clear_ds',
 );

sub BUILD {
    my $self = shift;
    my $args = shift;

    my $ds = $self->ds;
    $self->_clear_ds;

    $self->some_attr($ds->{...});
    $self->other_attr($ds->{foo}[3]);
    ...
} # end BUILD

Вы можете назвать метод считывателя как-нибудь еще (например, _ds), если хотите.

...