Ouch - Exceptions that don't hurt.
For the past many years I've been using Exception::Class to create rich, object-oriented exceptions. However, I've always disliked it, but I never found anything better. I felt like it was just too verbose and seemed to get in my way more often than it helped. Finally I created Ouch, a minimalist exception handling system. Details after the jump.
Ouch is an exception handler that tries as much as possible to give you the power of something like Exception::Class, but with a minimalist interface. To throw an exception, you simply ouch:
ouch 404, 'File not found.', 'filename';
Nothing needs to be defined in advance. Catching exceptions is just as easy:
if (kiss 404) {
do_something_with_the_exception($@);
}
Ouch also has an object oriented interface to do some more advanced things:
my $e = eval { ouch $code, $message, $data } || Ouch->new($code, $message, $data);
$e->trace; # full stack trace
$e->scalar || scalar $e; # File not found at Uploader.pm line 45.
$e->hashref; # { code => 404, message => 'File not found.', data => 'filename' }
$e->code; # 404
$e->message; # File not found.
$e->data; # filename
Ouch has a few other benefits. For one, since it uses exception codes rather than exception classes it is more friendly to work with in web interfaces, or anything else that uses status codes (HTTP, FTP, JSON-RPC, etc).
For another, it has a nice sugar function called bleep(), which removes the perlish stuff (stack trace, line numbers, etc) from an exception message (including non-Ouch exceptions). This can be incredibly useful if you want to display exception messages directly to an end user.
And finally, the data element is both optional and free form. You can throw any reference or scalar into it (so long as those references don't contain objects), which gives you some of the functionality of Exception::Class' "fields" parameter. I often find myself putting a field name into it to represent an exception thrown on a field where a user has entered inappropriate data. That makes it easy to highlight the field when I trap the exception.
In the module's documentation, I go into detail about why I think it's better than Exception::Class. What it really comes down to is that it's faster, smaller, has no dependencies, and costs a lot less typing. It's less than half that of Exception::Class.
Don't ge me wrong, I'm not saying Exception::Class is bad, or that you should ditch it. For what Exception::Class does, I've still found nothing better. However, if you're looking for good exception objects that are smaller and easier to use than Exception::Class, give Ouch a try. I've already switched a number of my projects over to it, and will be migrating all my CPAN modules in the coming weeks.
Like it. And pun-friendly too :)
The functions names ouch(), kiss() and bleep() seem opaque (and also a little too cute).
In particular kiss() doesn't give any indication of what it is doing:
if (kiss 404) { # do something }
Perhaps you wanted to avoid try()/catch() to avoid conflicts with other exception handling mechanisms but at least those names would make the functionality clear to a casual reader.
Confused me at first too, but this helps remembering: when something ouch()es, you kiss() it to make it better. :)
One small question: Why the decision to only use numbers for error codes, rather than strings? Not every problem domain uses numeric error codes; to take a random example offhand, XMPP uses named errors on the XML stream which don't easily associate with numbers.
You could easily test for equality with something like
This is great - I've been looking something to easily make exception objects for a while now, and I haven't particularly liked what I've found.
But I do agree that numerical codes are probably not that great. As a design decision, it would only make sense where errors are typically numerical, as you pointed out: HTTP, FTP...
For most (all?) other uses, the programmer typically wants a string so the error name can be descriptive so you don't have to remember which error number is which.
Would you consider allowing both numerical and string identifiers in a future release?
This is why I wrote Throwable and Throwable::X -- http://rjbs.manxome.org/rubric/entry/1860 and http://advent.rjbs.manxome.org/2010/2010-12-03.html and http://search.cpan.org/dist/HTTP-Throwable/
They're not super lightweight, but they're very easy to use. YMMV, of course.
This is why I wrote Throwable and Throwable::X -- http://rjbs.manxome.org/rubric/entry/1860 and http://advent.rjbs.manxome.org/2010/2010-12-03.html and http://search.cpan.org/dist/HTTP-Throwable/
They're not super lightweight, but they're very easy to use. YMMV, of course.
By popular request I will be putting out a new release today that adds the following functionality:
1) The ability to use text-based codes as well as numeric.
2) Aliases for ouch() and kiss() called throw() and catch() for those that don't like the sugary names. Though you will have to import these separately.
Excellent. Exactly what I've been looking for.