Moose Loose Ends Part the Sixth
Its dig deep an play day here in the Moose-Pen
I my last post I figured out how to set up Database:Accessor to get the 'MooseX::Constructor::AllErrors' object in the 'around BUILDARGS' and then play with it, without breaking my existing code.
Today I want to see if I can change my error messages. I started by poking about in guts of ' MooseX::Constructor::AllErrors' and I discovered the the error messages are rather had coded;
sub message {
my $self = shift;
return sprintf 'Attribute (%s) is required',
$self->attribute->name;
}
Now that does not do me much good as I can't just do this in my 'around' sub
eval{ $instance = $class->$orig($ops)};
if ($@) {
$@->errors[0]->message("I changed this");
...
and expect it to work. I will have to work something else out.
There is a 'misc' attribute on the 'AllErrors' I might be able to force that to my will. That attribute is and 'Array-ref' of 'MooseX::Constructor::AllErrors::Error::Mis' classes and that class has this attribute
has message => (
is => 'ro',
isa => 'Str',
required => 1,
);
All I need to do now is convert the other errors I am getting into 'Mis' errors and then return 'AllErrors' instance.
What I came up with first is
eval{ $instance = $class->$orig($ops)};
if ($@) {
foreach my $error ($@->missing()){
my $misc = MooseX::Constructor::AllErrors::Error::Misc->new(
message =>"Database::Accessor New Error: ".$error->message);
$@->add_error($misc);
}
die $@;
}
else {
return $instance;
}
In the 'around' and of course I added in a test;
eval {
$da = Database::Accessor->new({});
};
@errors = $@->errors;
ok( index($errors[2]->message,'Database::Accessor New Error: Attribute (elements) is required') >=0 , "New error added" );
and when I ran it I got;
…
ok 10 - View: param alias fails
ok 11 - Proper scalar error on empty build
ok 12 - New error added
That worked but now I have 3 errors when I should only have one. That I can deal with later.
What I want is to get a little more useful message in there. Right now I am only getting 'Database::Accessor New Error: Attribute (elements) is require' with no line, package or file name which is nice to have.
With the 'AllErrors' class I do have the access to calling info the 'caller' method which returns and array-ref of the calling info. I am going to add in line and file name to the new message like this
foreach my $error ($@->missing()){
my $misc = MooseX::Constructor::AllErrors::Error::Misc->new({message =>"Database::Accessor New Error: "
. $error->message
. " at Line "
. $@->caller->[2]
. " file: "
. $@->caller->[1]});
$@->add_error($misc);
}
and now I get;
Database::Accessor New Error: Attribute (elements) is required at Line 157 file: D:\GitHub\database-accessor\lib/Database/Accessor.pm
ok that is a little better but I am really not helping the end user much as I am only giving the location of where I called 'new' in the 'around' sub I can improve on that just a little more by first;
around BUILDARGS => sub {
my $orig = shift;
my $class = shift;
my $ops = shift(@_);
++ my ($package, $filename, $line, $subroutine) = caller(3);
adding my own caller in at the very begiining of 'around'. Note here I am using the optional $i to the 'caller' function. Using (3) here forces perl to get the calling subroutine which gets me out of the Moose stack and back to the orignal calling program. I can now give this a try
my $misc = MooseX::Constructor::AllErrors::Error::Misc->new({message =>"Database::Accessor New Error: "
. $error->message
. " at Line "
-- . $@->caller->[2]
++ . $line
. " file: "
-- . $@->caller->[1]});
++ . $filename});
$@->add_error($misc);
}
which gives me;
Database::Accessor New Error: Attribute (elements) is required at Line 135 file: 30_view.t
Perfect. Now to clean this all up, but that is a post for tomorrow.
Leave a comment