le soleil roi d'orignal
Its another re-factor day here in the Moose-Pen
I left off yesterday with a little re factoring to do. I had essentially the same code for handling construction errors in Accessor.pm and in Types.pm. In any other object orientated language I ever worked with this would be rather a pain to fix. Even in plain perl one would have a few problems getting things just right.
Fortunately I am using Moose.
The great thing about Moose a Role can consume another Role. So all I needed to do was suck out all the code I need from the 'around BUILDARGS' call in Accessor.pm and then place it in a separate role class 'Database::Accessor::Roles::AllErrors', create a function to call and then adapt it to run 'inline'.
By 'inline' I mean call the function as if it was an exposed function in some other module. That means I do not this the normal 'shift' at the start of a sub to get the calling instance.
My first effort is below;
package Database::Accessor::Roles::AllErrors;
use Moose::Role;
use MooseX::Constructor::AllErrors;
use Data::Dumper;
sub _one_error {
my ($ops) = @_;
my ( $package, $filename, $line, $subroutine ) = caller(3);
my @errors;
my $error_msg;
my $error;
if ( $@->missing() ) {
foreach my $error ( $@->missing() ) {
push(
@errors,
sprintf( '%s%s',
( $error->attribute->documentation )
? $error->attribute->documentation . "->"
: "",
$error->attribute->name() )
);
}
$error =
"The following Attribute"
. _is_are_msg( scalar(@errors) )
. "required: ("
. join( ",", @errors ) . ")\n";
}
if ( $@->invalid() ) {
@errors = ();
foreach my $error ( $@->invalid() ) {
push(
@errors,
sprintf(
"'%s%s' Constraint: %s",
( $error->attribute->documentation )
? $error->attribute->documentation . "->"
: "",
$error->attribute->name,
$error->attribute->type_constraint->get_message(
$error->data
)
)
);
}
$error .=
"The followling Attribute"
. _did_do_msg( scalar(@errors) )
. " not pass validation: \n"
. join( "\n", @errors );
}
my $misc =
"Database::Accessor new Error:\n"
. $error
. "\nWith constructor hash:\n"
. Dumper($ops);
my $die =
MooseX::Constructor::AllErrors::Error::Constructor->new(
caller => [ $package, $filename, $line, $subroutine ], );
$die->add_error(
MooseX::Constructor::AllErrors::Error::Misc->new(
{ message => $misc }
)
);
die $die;
}
sub _is_are_msg {
my ($count) = @_;
return "s are "
if ( $count > 1 );
return " is ";
}
sub _did_do_msg {
my ($count) = @_;
return "s do "
if ( $count > 1 );
return " did ";
}
1;
To start I will make my Types.pm file work with the above.
use strict;
package Database::Accessor::Types;
# ABSTRACT: A Types Role for Database::Accessor:
use Moose::Role;
++ with qw(Database::Accessor::Roles::AllErrors);
…
coerce 'Predicate', from 'HashRef',
via {
my $object;
eval {
$object = Database::Accessor::Predicate->new( %{$_} )
};
if ($@) {
_one_error($_);
}
return $object;
All I did was add in the 'with' and the class name and then cut out all the code from yesterday and call my '_one_error' sub directly. Farily easy stuff the only thing of note is that you cannot pass the error down into the sub it is a 'global' var so it will be shared by the sub.
On the first run I get an error call like this;
Database::Accessor new Error:
The following Attribute is required: (conditions->left)
With constructor hash:
{
'operator' => '=',
'right' => {
'value' => 'test'
},
'leftx' => {
'view' => 'People',
'name' => 'last_name'
},
'close_parentheses' => 0,
'condition' => 'AND',
'open_parentheses' => 1
}
at C:/Dwimperl/perl/site/lib/Moose/Meta/TypeConstraint.pm line 145
not too bad.
In about one minute I did the same change in the 'around BUILDARGS' sub
if ($@) {
if (exists($ENV{'DA_ALL_ERRORS'}) and $ENV{'DA_ALL_ERRORS'} ){
die $@;
}
else {
_one_error($_);
}
}
else {
return $instance;
}
much cleaner now and I don't even have to import the new role as I import the 'Database::Accessor::Types' role with already has it.
As a side note I do not really have to put this code in a 'role' I can just add it to the 'Types' role and things will work just fine. I created it as a role so it could be available to DAD writers who might want to use the same standard error in their code.
I still have to clean up the above a little but it is a start.
Leave a comment