Subject: | around 'new' => sub{ ... } and class attributes are code position dependend |
Date: | Fri, 19 Dec 2014 14:50:49 +0100 |
To: | bug-Moo [...] rt.cpan.org |
From: | Wolfgang Pecho <pecho [...] belwue.de> |
Hi,
perl 5.18.2
Moo: 1.006001 / 1.005000
if you do an "around 'new' " in Moo the object instantiation does not
know attributes
of the class, if the "attribute declaration" is given after the "around
'new' ".
example code :
--------------
package AroundNew;
use strict;
use warnings;
use Moo;
use MooX::StrictConstructor;
has 'x_attr' => (
is => 'rw',
required => 1,
);
around 'new' => sub {
my $orig = shift;
my $self = shift;
my $obj;
eval {
$obj = $self->$orig(@_);
};
if ($@) {
chomp($@);
print "--> ERROR: AroundNew::new() died with '$@'\n";
exit;
}
return $obj;
};
has 'y_attr' => (
is => 'rw',
required => 1,
);
1;
# in main
#!/usr/bin/env perl
use strict;
use warnings;
use AroundNew;
print "--> Try to instantiate object \n";
my $an = AroundNew->new( x_attr => 1 , y_attr => 2 );
print "x_attr: ", $an->x_attr, "\n";
print "y_attr: ", $an->y_attr, "\n";
print "--> Done\n";
-------------
The output of main is:
--> Try to instantiate object
--> ERROR: AroundNew::new() died with 'Found unknown attribute(s) passed
to the constructor: y_attr at (eval 23) line 57.'
Message is from MooX::StrictConstructor, which is used here just to make
the problem clear.
If you debug into the $self->$orig code, you find in
Method::Generate::Constructor:
53 # MooX::StrictConstructor
54==> my %attrs = ("x_attr" => 1,);
55: my @bad = sort grep { ! $attrs{$_} } keys %{ $args };
56: if (@bad) {
57: die("Found unknown attribute(s) passed to the
constructor: " .
58 join ", ", @bad);
y_attr is missing.
In the case you uncomment MooX::StrictConstructor you get the error:
--> Try to instantiate object
x_attr: 1
Use of uninitialized value in print at test_AroundNew.pl line 12.
y_attr:
--> Done
And debugging shows in Method::Generate::Constructor
51==> my $new = bless({}, $class);;
52: if (exists $args->{"x_attr"}) {
53: $new->{"x_attr"} = $args->{"x_attr"};
54 }
55: return $new;
y_attr is missing.
The code works if you put all attribute declarations above "around 'new' "
which gives Method::Generate::Constructor
51: my $new = bless({}, $class);;
52: if (exists $args->{"x_attr"}) {
53: $new->{"x_attr"} = $args->{"x_attr"};
54 }
55==> if (exists $args->{"y_attr"}) {
56: $new->{"y_attr"} = $args->{"y_attr"};
57 }
58: return $new;
or
you replace Moo by Moose (i.e. Moo -> Moose, MooX::StrictConstructor ->
MooseX::StrictConstructor).
Hope there is a chance to fix it.
Ciao
Wolfgang