Moose in a Dark Place

Still stuck in error land in the Moose-Pen.

As I finally got the 'add_condition' to work I still needed to add in a few more tests for the other three 'dynamic' attributes, gather, link and sort.

Well I started with the easiest first 'sort' and on the 'undef' I am getting the now very familiar;


Attribute (name) is required at D:\GitHub\database-accessor\lib/Database/Accessor/Types.pm line 348

It did not take me very long to back track this one to the '_element_coerce' sub in my 'Types' class;

As this had the same sort of fall though 'if' case like '_predicate_array_or_object' I at first added my check for undef code in the final 'if' of that statement;


...
else {
unless ($hash) {
my ( $package, $filename, $line, $subroutine ) = caller(4);
$subroutine =~ s/Database::Accessor:://g;
my $add = substr($subroutine,4,length($subroutine));
my $die =
MooseX::Constructor::AllErrors::Error::Constructor->new(
caller => [ $package, $filename, $line, $subroutine ], );
$die->add_error(
MooseX::Constructor::AllErrors::Error::Misc->new(
{
message => "Database::Accessor "
. $subroutine
. " Error:\n"
. "You cannot add undef to dynamic_"
. $add
. "! "
}
)
);
die $die;
}
if ( exists( $hash->{left} ) or exists( $hash->{right} ) ) {
my %copy = %{ Clone::clone($hash) };
delete( $copy{left} );
delete( $copy{right} );
$LAST = \%copy;

}
$object = Database::Accessor::Element->new( %{$hash} );


Silly me I actually though that would work but all I got was the same error;

Attribute (name) is required at D:\GitHub\database-accessor\lib/Database/Accessor/Types.pm line 371
except on a later line.

Well good old perl got me again as the earlier parts of the if statement;

if ( exists( $hash->{expression} ) ) {
$hash->{expression} = uc( $hash->{expression} );
$object = Database::Accessor::Expression->new( %{$hash} );
}

will automatiley convert the incomming 'undef' to an undefined hash ref '{}' so with what I have above will never work.

I had to move the code to the top of the if block and check for undef with an 'unless'


unless ($hash) {
my ( $package, $filename, $line, $subroutine ) = caller(4);
$subroutine =~ s/Database::Accessor:://g;
my $add = substr($subroutine,4,length($subroutine));
my $die =
MooseX::Constructor::AllErrors::Error::Constructor->new(
caller => [ $package, $filename, $line, $subroutine ], );
$die->add_error(
MooseX::Constructor::AllErrors::Error::Misc->new(
{
message => "Database::Accessor "
. $subroutine
. " Error:\n"
. "You cannot add undef to dynamic_"
. $add
. "! "
}
)
);
die $die;
}
elsif ( exists( $hash->{expression} ) ) {


and now I get that nice

Database::Accessor add_sort Error:
You cannot add undef to dynamic_sort! at 42_new_validation.t line 87#

Now at this point I think I can do a little re-factoring before I move over to the other two 'dynamic_' adds.

Before I did any refactoing I wanted to see what come out of a raw error on the above sub so I added in the test code to see what I get;


sub _element_coerce {
my ($hash) = @_;
++ eval {
++ $object = Database::Accessor::Element->new( %{$hash} );
++ };
++ warn("Error ref is ".ref($@))
++ if($@);
my $object;
$LAST = $hash;

and when I run my test again I get;

Error ref is MooseX::Constructor::AllErrors::Error::Constructon

which is just what I want to see as I can now reuse that '_one_error' sub in my 'AllErrors' role for this case. Now I just have to back track a little to the '_predicate_array_or_object' sub and start the re-factoring there.

The first thing I tried was


unless ($object) {
my ( $package, $filename, $line, $subroutine ) = caller(3);
$subroutine =~ s/Database::Accessor:://g;
$class =~ s/Database::Accessor:://g;
my $die =
MooseX::Constructor::AllErrors::Error::Constructor->new(
caller => [ $package, $filename, $line, $subroutine ], );
$die->add_error(
MooseX::Constructor::AllErrors::Error::Misc->new(
{
message => "Database::Accessor "
. $subroutine
. " Error:\n"
. "You cannot add undef to dynamic_"
. $class . "s! "
}
)
);
die $die;
}
push( @{$objects}, $class->new( { predicates => $object } ) );

and I got this;

Database::Accessor Error:
The following Attribute did not pass validation:
'condition->predicates' Constraint: Validation failed for 'Predicate' with value undef (not isa Database::Accessor::Predicate)
With constructor hash:
{
'predicates' => undef
}
at line 0

Which is a start at least I can pass down the correct 'class' and in '$opts' but I am not getting that nice udef error message with the correct line and file;

I can fix the file and line numbers by passing in the caller level with this change in the _create_instance sub;


sub _create_instance {
-- my ( $class, $ops ) = @_;
++ my ( $class, $ops,$caller ) = @_;

-- my ( $package, $filename, $line, $subroutine ) = caller(12);
++ my ( $package, $filename, $line, $subroutine ) = caller($caller);


and this change in '_predicate_array_or_object';

-- push( @{$objects}, _create_instance( $class, { predicates => $object }));
++ push( @{$objects}, _create_instance( $class, { predicates => $object },4));

What to note here is I bumped up the call level one to account for fact I am going to a deeper sub. On my next run I get;

...
at 42_new_validation.t line 88#

so the correct file and line #. Now for the message;

This proved to be very tricky as I could get this out whith undef;


Database::Accessor add_condition Error:
You cannot add 'undef' with add_condition at 42_new_validation.t line 85

however on my next test;

$da->add_condition( {
leftx => {
name => 'last_name',
view => 'People'
},
operator => undef
});

I was getting this message;

Database::Accessor add_condition Error:
With constructor hash:
{
'predicates' => {
'operator' => undef,
'leftx' => {
'view' => 'People',
'name' => 'last_name'
}
}
}
at 42_new_validation.t line 92

I should really be getting on2 like this;

Database::Accessor new Error:
The following Attribute is required: (conditions->left)
The following Attribute did not pass validation:
'conditions->operator' Constraint: The Operator 'undef', is not a valid Accessor Operator! Try one of '!=', '<', '<=', '<>', '=', '>', '>=', 'ALL', 'AND', 'ANY', 'BETWEEN', 'EXISTS', 'IN', 'IS NOT NULL', 'IS NULL', 'LIKE', 'NOT EXISTS', 'NOT IN', 'NOT LIKE', 'OR'
With constructor hash:
...

I did not find a solution yet but I did figure out what the problem was. I have a little recursion bug going on. When I create a 'condition' class I use the '_create_instance' sub to create it. The problems arises because to create a 'condition' I also have to create a 'predicate' and I also use the '_create_instance' to create that class thus I have a failed eval in a failed eval call and I get two 'AllErrors' objects one that is created by the first eval and then goes away with the second eval;

It did try a number of things even this bit of silliness


my $error = do {
local $@;
eval { $object = $class->new( %{$ops} ); };
$@;
};

to try an localize the error just did not work for me at least this late at night.

image1233.jpg

Leave a comment

About byterock

user-pic Long time Perl guy, a few CPAN mods allot of work on DBD::Oracle and a few YAPC presentations