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',

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);
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]});

and now I get;

Database::Accessor New Error: Attribute (elements) is required at Line 157 file: D:\GitHub\database-accessor\lib/Database/
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});
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. moose-calling-mark-little.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