NAME

Error::Base - Simple structured errors with full backtrace

VERSION

This document describes Error::Base version v0.1.4

SYNOPSIS

use Error::Base;
Error::Base->crash('Sanity check failed');  # die() with backtrace

my $err     = Error::Base->new('Foo');      # construct object first
    yourcodehere(...);                  # ... do other stuff
$err->crash;                                # as object method

my $err     = Error::Base->new(
                    'Foo error',            # odd arg is error text
                -quiet    => 1,             # no backtrace
                grink     => 'grunt',       # store somethings
                puppy     => 'dog',         # your keys, no leading dash 
            );
$err->crash;

$err->crank;                    # get cranky: warn() but don't die()
my $err = Error::Base->crank('Me!');        # also a constructor

eval{ Error::Base->crash( 'car', -foo => 'bar' ) }; 
my $err     = $@ if $@;         # catch and examine the full object

my $err     = Error::Base->new(
                -base       => 'File handler error:',
                _openerr    => 'Couldn\t open $file for $op',
            );
{
    my $file = 'z00bie.xxx';    # uh-oh, variable out of scope for new()
    open my $fh, '<', $file
        or $err->crash(
            -type       => $err->{_openerr},
            '$file'     => $file,
            '$op'       => 'reading',
        );                      # late interpolation to the rescue
}

DESCRIPTION

    J'avais cru plus difficile de mourir. -- Louis XIV

Die early, die often. Make frequent sanity checks and die when a check fails. See neat dumps of the caller stack with each error. Construct a group of error messages in one object or write error text ad hoc. Trap an error object and examine the contents; or let it tell its sad tale and end it.

Error::Base usage can be simple or complex. For quick sanity checks, construct and throw a simple fatal error in one line. At the other extreme, you can override methods in your own error subclasses.

Error::Base is lightweight. It defines no global variables, uses no non-core modules (and few of those), exports no symbols, and is purely object-oriented. I hope you will be able to use it commonly instead of a simple die(). You are not required to subclass it.

See the Error::Base::Cookbook for examples.

METHODS

new()

my $err     = Error::Base->new;             # constructor
my $err     = Error::Base->new(
                    'bartender',            # lone string first okay
                -base       => 'Bar error:',
                -type       => 'last call',
                -quiet      => 1,
                -top        => 3,
                -prepend    => '@! Black Tie Lunch:',
                -indent     => '@!                 ',
                _beer   => 'out of beer',   # your private attribute(s)
            );

The constructor must be called as a class method; there is no mutator returning a new object based on an old one. You do have some freedom in how you call, though.

Called with an even number of args, they are all considered key/value pairs. Keys with leading dash ('-') are reserved for use by Error::Base; keys led by a Perlish sigil (=~ /^[\$\@%]/) trigger late interpolation; all other keys are free to use as you see fit. Error message text is constructed as a single string.

Called with an odd number of args, the first arg is shifted off and appended to the error message text. This shorthand may be offensive to some; in which case, don't do that. Instead, pass -base, -type, or both.

You may stash any arbitrary data inside the returned object (during construction or later) and do whatever you like with it. You might choose to supply additional optional texts for later access.

Stringification is overridden on objects of this class. So, if you attempt to print the object, or perform an operation that causes perl to want to treat it as a string, you will get the printable error message. If you prefer to examine the object internally, access its hash values; or dump it using Data::Dumper, Devel::Comments, or Test::More::explain().

See "PARAMETERS".

crash()

Error::Base->crash('Sanity check failed');  # as class method
$err->crash;                                # as object method
    # all the same args are okay in crash() as in new()
eval{ $err->crash };                        # trap...
print STDERR $@ if $@;                      # ... and examine the object

crash() and other public methods may be called as class or object methods. If called as a class method, then new() is called internally. Call new() first if you want to call crash() as an object method.

crash() is a very thin wrapper, easy to subclass. It differs from similar methods in that instead of returning its object, it die()-s with it. If uncaught, the error will stringify; if caught, the entire object is yours.

crank()

$err->crank( -type => 'Excessive boxes' ) if $box > $max;

This is exactly like crash() except that it warn()s instead of die()-ing. Therefore you may easily recover the object for later use.

cuss()

my $err = Error::Base->cuss('x%@#*!');      # also a constructor

Again, exactly like crash() or crank() except that it neither die()-s nor warn()s; it only returns the object.

The difference between new() and the other methods is that new() returns the constructed object containing only what was passed in as arguments. crash(), crank(), and cuss() perform a full stack backtrace (if not passed -quiet) and format the result for stringified display.

You may find cuss() useful in testing your subclass or to see how your error will be thrown without the bother of actually catching crash().

init()

$err->init(@args);

The calling conventions are exactly the same as for the other public methods.

init() is called on a newly constructed object, as is conventional. If you call it a second time on an existing object, new @args will overwrite previous values. Internally, when called on an existing object, crash(), crank(), and cuss() each call init(). When these are called as class methods, they call new(), which calls init().

Therefore, the chief distinction between calling as class or object method is that if you call new() first then you can separate the definition of your error text from the actual throw.

PARAMETERS

All public methods accept the same arguments, with the same conventions. All parameter names begin with a leading dash ('-'); please choose other names for your private keys.

If the same parameter is set multiple times, the most recent argument completely overwrites the previous value.

You are cautioned that deleting keys may be unwise.

-base

scalar string

The value of -base is printed in the first line of the stringified error object after a call to crash(), crank(), or cuss().

-type

scalar string

This parameter is provided as a way to express a subtype of error. It is appended to -base.

-pronto

scalar string

$err->crash( 'Pronto!' );           # emits 'Pronto!'
$err->crash(
        -pronto => 'Pronto!',
);                                  # same thing

As a convenience, if the number of arguments passed in is odd, then the first arg is shifted off and appended to the error message after -base and -type. This is done to simplify writing one-off, one-line sanity checks:

open( my $in_fh, '<', $filename )
    or Error::Base->crash("Couldn't open $filename for reading.");

TODO: It is expected that each message argument be a single scalar. If you need to pass a multi-line string then please embed escaped newlines ('\n').

-quiet

scalar boolean default: undef

$err->crash( -quiet         => 1, );        # no backtrace

By default, you get a full stack backtrace. If you want none, set this parameter. Only error text will be emitted.

-top

scalar unsigned integer default: 2

By default, stack frames internal to Error::Base are not traced. Set this parameter to adjust how many frames to discard.

TODO: A more elegant interface.

-prepend

scalar string default: undef

-indent

scalar string default: first char of -prepend, padded with spaces to length

-prepend_all

scalar string default: undef

The value of -prepend is prepended to the first line of error text; -indent to all others. If given, -prepend_all overrides the other parameters and is prepended to all lines.

This is a highly useful feature that improves readability in the middle of a dense dump. So in future releases, the default may be changed to form -prepend in some way for you if not defined. If you are certain you want no prepending or indentation, pass the empty string, q{}.

LATE INTERPOLATION

It is possible to interpolate a variable that is not in scope into error message text. This is triggered by passing the value against a key whose leading character is a Perlish sigil, one of $@%. Enclose the text (including placeholders) in single quotes. For a detailed explanation, see the Cookbook.

RESULTS

Soon, I'll write accessor methods for all of these. For now, rough it.

-msg

scalar string default: 'Undefined error.'

The error message, expanded, without -prepend or backtrace. An empty message is not allowed; if none is provided by any means, 'Undefined error.' emits.

-lines

array of strings

The formatted error message, fully expanded, including backtrace.

-frames

array of hashrefs

The raw stack frames used to compose the backtrace.

SUBCLASSING

use base 'Error::Base';
sub init{
    my $self    = shift;
    _munge_my_args(@_);
    $self->SUPER::init(@_);
    return $self;
};

While useful standing alone, Error::Base is written to be subclassed, if you so desire. Perhaps the most useful method to subclass may be init(). You might also subclass crash(), crank(), or cuss() if you want to do something first:

use base 'Error::Base';
sub crash{
    my $self    = _fuss(@_);
    $self->a_kiss_before_dying();
    die $self;
};

The author hopes that most users will not be driven to subclassing but if you do so, successfully or not, please be so kind as to notify.

SEE ALSO

Error::Base::Cookbook

Many error-related modules are available on CPAN. Some do bizarre things.

Exception::Class, Error, Exception, Carp, Test::Trap.

INSTALLATION

This module is installed using Module::Build.

DIAGNOSTICS

This module emits error messages for you; it is hoped you won't encounter any from within itself. If you do see one of these errors, kindly report to RT so maintainer can take action. Thank you for helping.

All errors internal to this module are prefixed Error::Base internal...

excessive backtrace

Attempted to capture too many frames of backtrace. You probably mis-set -top, rational values of which are perhaps 0..9.

unpaired args:

You do not have to pass paired arguments to most public methods. Perhaps you passed an odd number of args to a private method.

bad reftype

You attempted to late-interpolate a reference other than to a scalar, array, or hash. Don't pass such references as values to any key with the wrong sigil.

no $self

Called a method without class or object. Did you call as function?

stringifing unthrown object

An object of this class will stringify to its printable error message (including backtrace if any) when thrown. There is nothing to see (yet) if you try to print an object that has been constructed but not (yet) thrown. This error is not fatal; it is returned as the stringification.

in _late eval:

Attempted to late-interpolate badly. Check your code. The interpolation failed so you cannot expect to see the correct error message text. On the offchance that you would like to see the stack backtrace anyway, this error is not fatal.

CONFIGURATION AND ENVIRONMENT

Error::Base requires no configuration files or environment variables.

DEPENDENCIES

There are no non-core dependencies.

version 0.94 # Perl extension for Version Objects

overload # Overload Perl operations

Scalar::Util # General-utility scalar subroutines

This module should work with any version of perl 5.8.8 and up.

INCOMPATIBILITIES

None known.

BUGS AND LIMITATIONS

This is an early release. Reports and suggestions will be warmly welcomed.

Please report any bugs or feature requests to bug-error-base@rt.cpan.org, or through the web interface at http://rt.cpan.org.

THANKS

Grateful acknowledgement deserved by AMBRUS for coherent API suggestions. Any failure to grasp them is mine.

AUTHOR

Xiong Changnian <xiong@cpan.org>

LICENSE

Copyright (C) 2011 Xiong Changnian <xiong@cpan.org>

This library and its contents are released under Artistic License 2.0:

http://www.opensource.org/licenses/artistic-license-2.0.php