Still Cleaning Moose

Still in mop up mode here in the Moose-Pen

I finally found a way (well not a good one) to generate an even better error message to my end users. You are of course quite familiar with this type of message;

Database::Accessor add_condition Error:
The following Attribute is required: (Element->name)

With constructor hash:
'operator' => '=',
'left' => {
'view' => 'People',
'name' => 'last_name'
'right' => {
'left' => {
'name' => 'salary'
'right' => {
'expressionx' => '*'
'function' => 'LEFT'
'close_parentheses' => 0,
'condition' => 'AND',
'open_parentheses' => 1

Very hard to find out that it is the 'expressionx' that is giving us grief. With the changes I have just completed I now get

The following Attribute is required: (Element->name)
Possiable missing/invalid key in or near:
'expressionx' => '*'
With constructor hash:

which leads me right to the right spot. Now for the explication of shame;

I had to resort to using another global var to get this to work. Not something I like to do.
To start I added it in at the top of the “Types” class

package Database::Accessor::Types;
our $NEW;
++our $LAST;

then way down in the '_element_coerce' sub I set it to the incoming '$hash'

sub _element_coerce {
my ($hash) = @_;
my $object;

++ $LAST=$hash;

now the if testaments that follow the above;

if ( exists( $hash->{expression} ) ) {
$hash->{expression} = uc( $hash->{expression} );
$object = Database::Accessor::Expression->new( %{$hash} );
elsif ( exists( $hash->{function} ) ) {
$hash->{function} = uc( $hash->{function} );
$object = Database::Accessor::Function->new( %{$hash} );
elsif ( exists( $hash->{value} ) || exists( $hash->{param} ) ) {
$object = Database::Accessor::Param->new( %{$hash} );
elsif ( exists( $hash->{ifs} ) ) {
die "Attribute (ifs) does not pass the type constraint because:
Validation failed for 'ArrayRefofThens' with less than 2 ifs"
if ( exists( $hash->{ifs} )
and ref( $hash->{ifs} ) eq 'ARRAY'
and scalar( @{ $hash->{ifs} } < 2 ) );

$object = Database::Accessor::If->new( %{$hash} );
else {
++ 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} );
++ $LAST= undef;
return $object;

Will always either end in a success or fall though to the last 'else' where if the left or right keys exists I know I am in an error condition. I fist Clone the ref into a new Hash. This is done so I will get the correct 'constructor' hash on my error message, otherwise when I delete those two keys, they will be missing in that 'constructor' hash. I found that the really are just taking up space and without them the message reads much better. Finally I set my $LAST to a ref of the cloned %copy and then just let the 'Element->new' fail.

I also had to make a change to my '' sub in the 'AllErrors;' role as well by adding in a little flag

$error_package = $missing->attribute->definition_context->{package};

to capture the 'package' of the error. I then use that a little later on in this block;

++ my $on ="";
++ if ($error_package eq "Database::Accessor::Element"){
++ $on = " Possible missing/infalid key in or near:\n"
++ . Dumper($Database::Accessor::Types::LAST);
++ }

my $misc =
"Database::Accessor "
. $call
. " Error:\n"
. $error
++ . $on
. "With constructor hash:\n"
. Dumper($ops);

To check that I have an error in my 'Element' class and then put the location message in the $on var and then add that to the error message.

Well that is about it. I do not think I can squeeze any more out of the error capture. On to other things tomorrow.


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