The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Error::Base - Simple structured errors with full backtrace

VERSION

This document describes Error::Base version v1.0.1

WHAT'S NEW

  • You may now pass an array reference to -mesg.

  • You now have get and put accessors.

  • Some elements of the API have changed. -top and -prepend_all have been deprecated.

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
    
    # late interpolation
    my $err     = Error::Base->new(
                    -base       => 'File handler error:',
                    _openerr    => 'Could not 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,
                    -nest       => 1,
                    -prepend    => '@! Black Tie Lunch:',
                    -indent     => '@!                 ',
                    _beer   => 'out of beer',   # your private attribute(s)
                );
    my $err     = Error::Base->new(
                    -base       => 'First',
                    -type       => 'Second',
                    -mesg       => 'Third',
                );

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, and/or -mesg.

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. 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.

-mesg

scalar string or array reference

    $err->crash( 'Pronto!' );           # emits 'Pronto!'
    $err->crash(
            -mesg => 'Pronto!',
    );                                  # same thing
    my $foo     = 'bar';
    $err->crash(
            -mesg => [ 'Cannot find', $foo, q{.} ],
    );                                  # emits 'Cannot find bar .'

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.");

You may pass into -mesg a reference to an array of simple scalars; these will all be joined together and appened to the error message. 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

Deprecated as a public parameter; now internal only to Error::Base.

-nest

scalar signed integer default: 0

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

-prepend

scalar string default: undef

-indent

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

The value of -prepend is prepended to the first line of error text; -indent to all others. If only -indent is given, it is prepended to all lines. If only -prepend is given, -indent is generated from its first character and padded to the same length. Override either of these default actions by passing the empty string.

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

-all

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.

ACCSESSORS

Object-oriented accessor methods are provided for each parameter and result. They all do just what you'd expect.

    $self               = $self->put_base($string);
    $self               = $self->put_type($string);
    $self               = $self->put_mesg($string);
    $self               = $self->put_quiet($string_or_aryref);
    $self               = $self->put_nest($signed_int);
    $self               = $self->put_prepend($string);
    $self               = $self->put_indent($string);
    $string             = $self->get_base();
    $string             = $self->get_type();
    $string_or_aryref   = $self->get_mesg();
    $boolean            = $self->get_quiet();
    $signed_int         = $self->get_nest();
    $string             = $self->get_prepend();
    $string             = $self->get_indent();
    $string             = $self->get_all();
    @array_of_strings   = $self->get_lines();
    @array of hashrefs  = $self->get_frames();

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 -nest, reasonable values of which are perhaps -2..3.

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 in _late

Perhaps 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.

bad reftype in _expand_ref

You passed a hashref or coderef to -mesg. Pass a simple string or arrayref.

no $self

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

stringifying 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.88      # 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. However, you may need to upgrade some core modules.

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.

DEVELOPMENT

This project is hosted on GitHub at: https://github.com/Xiong/error-base.

THANKS

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

AUTHOR

Xiong Changnian <xiong@cpan.org>

LICENCE

Copyright (C) 2011, 2013 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