Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make all lazy Moose features be built?

Tags:

perl

moose

I have a bunch of lazy features in a Moose object.

Some of the builders require some time to finish.

I would like to nvoke all the builders (the dump the "bomplete" object). Can I make all the lazy features be built at once, or must I call each feature manually to cause it builder to run?

like image 953
David B Avatar asked Nov 19 '10 14:11

David B


3 Answers

If you want to have "lazy" attributes with builders, but ensure that their values are constructed before new returns, the usual thing to do is to call the accessors in BUILD.

sub BUILD {
    my ($self) = @_;

    $self->foo;
    $self->bar;
}

is enough to get the job done, but it's probably best to add a comment as well explaining this apparently useless code to someone who doesn't know the idiom.

like image 159
hobbs Avatar answered Nov 04 '22 17:11

hobbs


Maybe you could use the meta class to get list of 'lazy' attributes. For example:

package Test;

use Moose;


has ['attr1', 'attr2'] => ( is => 'rw', lazy_build => 1);
has ['attr3', 'attr4'] => ( is => 'rw',);

sub BUILD {
    my $self = shift;


    my $meta = $self->meta;

         foreach my $attribute_name ( sort $meta->get_attribute_list ) {

         my $attribute =  $meta->get_attribute($attribute_name);

        if ( $attribute->has_builder ) {
            my $code = $self->can($attribute_name);
            $self->$code;

        }
    }

}


    sub _build_attr1 { 1 }
    sub _build_attr2 { 1 }
like image 37
jira Avatar answered Nov 04 '22 17:11

jira


I've had this exact requirement several times in the past, and today I actually had to do it from the metaclass, which meant no BUILD tweaking allowed. Anyway I felt it would be good to share since it basically does exactly what ether mentioned:

'It would allow marking attributes "this is lazy, because it depends on other attribute values to be built, but I want it to be poked before construction finishes."'

However, derp derp I have no idea how to make a CPAN module so here's some codes: https://gist.github.com/TiMBuS/5787018

Put the above into Late.pm and then you can use it like so:

package Thing;
use Moose;
use Late;

has 'foo' => (
    is      => 'ro',
    default => sub {print "setting foo to 10\n"; 10},
);

has 'bar' => (
    is      => 'ro',
    default => sub {print 'late bar being set to ', $_[0]->foo*2, "\n"; $_[0]->foo*2},
    late    => 1,
);

#If you want..
__PACKAGE__->meta->make_immutable;
1;


package main;

Thing->new();
#`bar` will be initialized to 20 right now, and always after `foo`.
#You can even set `foo` to 'lazy' or 'late' and it will still work.
like image 42
Jarrod Funnell Avatar answered Nov 04 '22 18:11

Jarrod Funnell