We're slowly refactoring our large Perl application towards object-oriented interfaces, especially for data models. The annoying part is that stack traces get less useful. To give a fabricated example: Before.
sub send_message {
my ($user_id, $message) = @_;
...
Carp::confess('test');
}
# output:
test at example.pm line 23
foo('42', 'Hello World') called at example.pl line 5
After.
sub send_message {
my ($user, $message) = @_;
...
Carp::confess('test');
}
# output:
test at example.pm line 23
foo('MyApp::Model::User=HASH(0x2c94f68)', 'Hello World') called at example.pl line 5
So now I cannot see which user was passed to foo()
, I only see the class name (which is already documented) and some memory address of an object.
I tried to install a stringification operator on the model class using overload.pm:
use overload ( '""' => \&stringify );
sub stringify {
my ($self) = @_;
return sprintf '%s[id=%d]', ref($self), $self->id;
}
But this does not affect the longmess. What I would like is something like this:
test at example.pm line 23
foo('MyApp::Model::User[id=42]', 'Hello World') called at example.pl line 5
That is, the first parameter to foo()
should be displayed using the object's stringify()
method. How can I achieve that?
The problem is in this part of
Carp.pm
:That is, when an argument could be an overloaded object, then any stringification overloading is circumvented with the
StrVal
helper, which forces default stringification.Unfortunately, there is no straightforward way around that. All we can do is monkey-patch the
Carp::format_arg
sub, e.g.As it is, this is inelegant, and should be put into a pragma:
File
Carp/string_overloading.pm
:Then the code
outputs: