thanks, Jesse, that works for me. I did know that.. pretty sure I won't forget it again! 8)
J On Fri, Jan 27, 2012 at 1:01 PM, Jesse Luehrs <d...@tozt.net> wrote: > On Fri, Jan 27, 2012 at 12:51:40PM +1000, Jason Galea wrote: > > Hi all, > > > > I need to stop looking at this.. I have a headache now.. > > > > I'm messing around with building a Plack app and had some really odd > > behaviour which I tracked back and boiled down to the test cases below. > > (unfortunately the result was my app connecting to a separate dev > database > > after creating an empty test database and telling me a user existed > where I > > knew it didn't.. took me a while to get past that..) > > > > anyhoo.. can someone please explain the oddities I'm seeing in these > tests? > > > > My::Builder works as expected until I call make_immutable on it, then it > > returns undef. > > > > My::Builder2 is the same as My::Builder except > > - the 'app' attribute is lazy. > > - it's been made immutable > > it works as expected. > > > > My:Builder3 is the same as My::Builder except > > - it's been made immutable > > - I renamed the 'app' attribute as 'attr2'.. > > it works as expected. > > > > My::Builder4 is the same as My::Builder except > > - attr1 uses lazy_build > > - it's been made immutable > > it fails, but it returns attr1's default value > > > > please tell me I'm doing something stupid so I can stop trying to work it > > all out.. 8) > > > > cheers, > > > > J > > > > use strict; > > use warnings; > > use Test::More; > > > > { > > package My::Builder; > > use Moose; > > > > has attr1 => ( is => 'ro', default => 'default value' ); > > > > has app => ( is => 'ro', builder => '_build_app' ); > > > > sub _build_app{ shift->attr1; } > > > > sub web_app{ > > my $self = shift; > > return sub { $self->app }; > > } > > > > > > > > package My::Builder2; > > use Moose; > > > > has attr1 => ( is => 'ro', default => 'default value' ); > > > > has app => ( is => 'ro', builder => '_build_app', lazy => 1 ); > > > > sub _build_app{ shift->attr1; } > > > > sub web_app{ > > my $self = shift; > > return sub { $self->app }; > > } > > > > __PACKAGE__->meta->make_immutable; > > > > > > package My::Builder3; > > use Moose; > > > > has attr1 => ( is => 'ro', default => 'default value' ); > > > > has attr2 => ( is => 'ro', builder => '_build_attr2' ); > > > > sub _build_attr2{ shift->attr1; } > > > > sub web_app{ > > my $self = shift; > > return sub { $self->attr2 }; > > } > > > > __PACKAGE__->meta->make_immutable; > > > > > > package My::Builder4; > > use Moose; > > > > has attr1 => ( is => 'ro', lazy_build => 1 ); > > sub _build_attr1{ 'default value' } > > > > has app => ( is => 'ro', builder => '_build_app' ); > > > > sub _build_app{ shift->attr1; } > > > > sub web_app{ > > my $self = shift; > > return sub { $self->app }; > > } > > > > __PACKAGE__->meta->make_immutable; > > > > } > > > > my $app = My::Builder->new( attr1 => 'my value' )->web_app; > > is $app->(), 'my value', 'no make immutable or lazy ok'; > > > > $app = My::Builder2->new( attr1 => 'my value' )->web_app; > > is $app->(), 'my value', 'make_immutable with lazy ok'; > > > > $app = My::Builder3->new( attr1 => 'my value' )->web_app; > > is $app->(), 'my value', 'make_immutable without lazy breaks.. not!'; > > > > My::Builder->meta->make_immutable; > > $app = My::Builder->new( attr1 => 'my value' )->web_app; > > is $app->(), 'my value', 'make_immutable without lazy breaks (returns > > undef)'; > > > > $app = My::Builder4->new( attr1 => 'my value' )->web_app; > > is $app->(), 'my value', 'make_immutable without lazy breaks (returns > > default value)'; > > > > done_testing(); > > > > > > $ prove -lv t/999-make-immutable-breaksit.t > > t/999-make-immutable-breaksit.t .. > > ok 1 - no make immutable or lazy ok > > ok 2 - make_immutable with lazy ok > > ok 3 - make_immutable without lazy breaks.. not! > > not ok 4 - make_immutable without lazy breaks (returns undef) > > > > # Failed test 'make_immutable without lazy breaks (returns undef)' > > # at t/999-make-immutable-breaksit.t line 86. > > # got: undef > > # expected: 'my value' > > not ok 5 - make_immutable without lazy breaks (returns default value) > > > > # Failed test 'make_immutable without lazy breaks (returns default > value)' > > # at t/999-make-immutable-breaksit.t line 89. > > # got: 'default value' > > # expected: 'my value' > > 1..5 > > # Looks like you failed 2 tests of 5. > > Dubious, test returned 2 (wstat 512, 0x200) > > Failed 2/5 subtests > > > > Test Summary Report > > ------------------- > > t/999-make-immutable-breaksit.t (Wstat: 512 Tests: 5 Failed: 2) > > Failed tests: 4-5 > > Non-zero exit status: 2 > > Files=1, Tests=5, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.18 cusr > 0.01 > > csys = 0.21 CPU) > > Result: FAIL > > This actually doesn't have anything to do with make_immutable. The issue > is that attributes without lazy are initialized in an arbitrary order, > so when the 'app' attribute is initialized (at 'new' time, since it > isn't lazy), it might be initialized before attr1, and it might be > initialized after. The only way to guarantee the order is to make app > lazy. A good rule of thumb is that any attribute whose default or > builder depends on the value of another attribute should be lazy. > > -doy > -- Jason Galea Web Developer Ph 07 40556926 Mob 04 12345 534 www.eightdegrees.com.au