Skip Menu |

This queue is for tickets about the Moo CPAN distribution.

Report information
The Basics
Id: 65897
Status: resolved
Worked: 30 min
Priority: 0/
Queue: Moo

People
Owner: Nobody in particular
Requestors: rdb [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: lazy_build support
Is it really THAT bad? :) You put all the options that make it work into Moo, but not this convenient alias. I'm interested in trying Moo but this is a sticking point, I'm not excited about exchanging lots of "lazy_build => 1" for four (or however many) other options that mean the same thing. I could send a patch if you like... :)
The attached diff (patch -p1 < lazy_build.patch) adds lazy_build support, as documented in Moose::Meta::Attribute, with tests.
Subject: lazy_build.patch
diff -uwrN /home/rob/.cpan/build/Moo-0.009007-1aslgY/lib/Method/Generate/Accessor.pm ./lib/Method/Generate/Accessor.pm --- /home/rob/.cpan/build/Moo-0.009007-1aslgY/lib/Method/Generate/Accessor.pm 2011-02-25 08:18:13.000000000 -0800 +++ ./lib/Method/Generate/Accessor.pm 2011-03-16 13:20:46.000000000 -0700 @@ -28,6 +28,40 @@ } elsif ($is ne 'bare') { die "Unknown is ${is}"; } + + if ($spec->{lazy_build}) { + # sanity check + + die "You can not use lazy_build and default for the same attribute ($name)" + if exists $spec->{default}; + + # According to Moose::Meta::Attribute, lazy_build sets: + # + # lazy => 1, + # builder => _build_foo + # predicate => has_foo + # clearer => clear_foo + + # If your attribute starts with an underscore, then the clearer + # and predicate will as well: + # + # lazy => 1 + # builder => _build__foo + # predicate => _has_foo + # clearer => _clear_foo + + $spec->{lazy} = 1; + $spec->{builder} = '_build_'.$name unless $spec->{builder}; + + if ($name =~ /^_/) { + $spec->{predicate} = '_has'.$name unless $spec->{predicate}; + $spec->{clearer} = '_clear'.$name unless $spec->{clearer}; + } else { + $spec->{predicate} = 'has_'.$name unless $spec->{predicate}; + $spec->{clearer} = 'clear_'.$name unless $spec->{clearer}; + } + } + my %methods; if (my $reader = $spec->{reader}) { if (our $CAN_HAZ_XS && $self->is_simple_get($name, $spec)) { diff -uwrN /home/rob/.cpan/build/Moo-0.009007-1aslgY/t/accessor-lazy_build.t ./t/accessor-lazy_build.t --- /home/rob/.cpan/build/Moo-0.009007-1aslgY/t/accessor-lazy_build.t 1969-12-31 16:00:00.000000000 -0800 +++ ./t/accessor-lazy_build.t 2011-03-16 13:16:37.000000000 -0700 @@ -0,0 +1,61 @@ +use strictures 1; +use Test::More; + +{ + package Foo; + + use Moo; + + has one => (is => 'ro', lazy_build => 1); + + sub _build_one { 3 } +} + +my $foo = Foo->new; + +ok(!$foo->has_one, 'empty'); +is($foo->one, 3, 'lazy default'); +ok($foo->has_one, 'not empty now'); +is($foo->clear_one, 3, 'clearer returns value'); +ok(!$foo->has_one, 'clearer empties'); +is($foo->one, 3, 'default re-fired'); +ok($foo->has_one, 'not empty again'); + +# attribute names that begin with '_' + +{ + package Bar; + + use Moo; + + has _two => (is => 'ro', lazy_build => 1); + + sub _build__two { 3 } +} + +my $bar = Bar->new; + +ok(!$bar->_has_two, 'empty'); +is($bar->_two, 3, 'lazy default'); +ok($bar->_has_two, 'not empty now'); +is($bar->_clear_two, 3, 'clearer returns value'); +ok(!$bar->_has_two, 'clearer empties'); +is($bar->_two, 3, 'default re-fired'); +ok($bar->_has_two, 'not empty again'); + +# sanity check + +eval { + package Baz; + + use Moo; + + has three => (is => 'ro', lazy_build => 1, default => 1); + + sub _build_three { 3 } + +}; + +ok ($@ =~ /lazy_build and default/, 'catches invalid options'); + +done_testing;
On Wed Mar 16 16:30:41 2011, RDB wrote: Show quoted text
> The attached diff (patch -p1 < lazy_build.patch) adds lazy_build > support, as documented in Moose::Meta::Attribute, with tests.
We implemented "is => 'lazy'" as supported by MooseX::AttributeShortcuts instead - which is what I wish lazy_build did (it got pushed down into Moose core without my really paying attention, and made a lot less sense there than it did in its original home in Reaction).