开发者

How can I require a Moose constructor arg that is not a attribute?

开发者 https://www.devze.com 2023-01-22 12:42 出处:网络
I have a Moose object module that should accept a relatively large data structur开发者_如何学Pythone (ds) as one of its constructor arguments. It is used to calculate some of the object\'s attributes.

I have a Moose object module that should accept a relatively large data structur开发者_如何学Pythone (ds) as one of its constructor arguments. It is used to calculate some of the object's attributes. However, I do not wish to store ds itself as an attributes -- it is only needed during the construction of the object.

I thought of using BUILDARGS but then I'm not sure how to define that ds is a required argument.

How can I work around this?


I'd be inclined to have a constructor that takes only the calculated values derived from your data structure. Then use a different method to take limited params plus the data structure as args.

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;
}

Then make your objects like so:

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

Now you don't have to worry about weird serialization issues or BUILDARGS or even BUILD. You have a simple method and that is all.


You could use either BUILD or BUILDARGS for this. It's hard to say which would be better without knowing more about what you're trying to do, but I'd guess BUILD would be the better choice.

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

If you want Moose to check the type and ensure it's present, you have to make it an attribute. But you can clear it in the BUILD method after you use it.

 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

You could name the reader method something else (like _ds) if you wanted to.

0

精彩评论

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

关注公众号