Blame README.md

Packit Service 3b7cb7
# NAME
Packit Service 3b7cb7
Packit Service 3b7cb7
Exception::Class - A module that allows you to declare real exception classes in Perl
Packit Service 3b7cb7
Packit Service 3b7cb7
# VERSION
Packit Service 3b7cb7
Packit Service 3b7cb7
version 1.44
Packit Service 3b7cb7
Packit Service 3b7cb7
# SYNOPSIS
Packit Service 3b7cb7
Packit Service 3b7cb7
    use Exception::Class (
Packit Service 3b7cb7
        'MyException',
Packit Service 3b7cb7
Packit Service 3b7cb7
        'AnotherException' => { isa => 'MyException' },
Packit Service 3b7cb7
Packit Service 3b7cb7
        'YetAnotherException' => {
Packit Service 3b7cb7
            isa         => 'AnotherException',
Packit Service 3b7cb7
            description => 'These exceptions are related to IPC'
Packit Service 3b7cb7
        },
Packit Service 3b7cb7
Packit Service 3b7cb7
        'ExceptionWithFields' => {
Packit Service 3b7cb7
            isa    => 'YetAnotherException',
Packit Service 3b7cb7
            fields => [ 'grandiosity', 'quixotic' ],
Packit Service 3b7cb7
            alias  => 'throw_fields',
Packit Service 3b7cb7
        },
Packit Service 3b7cb7
    );
Packit Service 3b7cb7
    use Scalar::Util qw( blessed );
Packit Service 3b7cb7
    use Try::Tiny;
Packit Service 3b7cb7
Packit Service 3b7cb7
    try {
Packit Service 3b7cb7
        MyException->throw( error => 'I feel funny.' );
Packit Service 3b7cb7
    }
Packit Service 3b7cb7
    catch {
Packit Service 3b7cb7
        die $_ unless blessed $_ && $_->can('rethrow');
Packit Service 3b7cb7
Packit Service 3b7cb7
        if ( $_->isa('Exception::Class') ) {
Packit Service 3b7cb7
            warn $_->error, "\n", $_->trace->as_string, "\n";
Packit Service 3b7cb7
            warn join ' ', $_->euid, $_->egid, $_->uid, $_->gid, $_->pid, $_->time;
Packit Service 3b7cb7
Packit Service 3b7cb7
            exit;
Packit Service 3b7cb7
        }
Packit Service 3b7cb7
        elsif ( $_->isa('ExceptionWithFields') ) {
Packit Service 3b7cb7
            if ( $_->quixotic ) {
Packit Service 3b7cb7
                handle_quixotic_exception();
Packit Service 3b7cb7
            }
Packit Service 3b7cb7
            else {
Packit Service 3b7cb7
                handle_non_quixotic_exception();
Packit Service 3b7cb7
            }
Packit Service 3b7cb7
        }
Packit Service 3b7cb7
        else {
Packit Service 3b7cb7
            $_->rethrow;
Packit Service 3b7cb7
        }
Packit Service 3b7cb7
    };
Packit Service 3b7cb7
Packit Service 3b7cb7
    # without Try::Tiny
Packit Service 3b7cb7
    eval { ... };
Packit Service 3b7cb7
    if ( my $e = Exception::Class->caught ) { ... }
Packit Service 3b7cb7
Packit Service 3b7cb7
    # use an alias - without parens subroutine name is checked at
Packit Service 3b7cb7
    # compile time
Packit Service 3b7cb7
    throw_fields error => "No strawberry", grandiosity => "quite a bit";
Packit Service 3b7cb7
Packit Service 3b7cb7
# DESCRIPTION
Packit Service 3b7cb7
Packit Service 3b7cb7
**RECOMMENDATION 1**: If you are writing modern Perl code with [Moose](https://metacpan.org/pod/Moose) or
Packit Service 3b7cb7
[Moo](https://metacpan.org/pod/Moo) I highly recommend using [Throwable](https://metacpan.org/pod/Throwable) instead of this module.
Packit Service 3b7cb7
Packit Service 3b7cb7
**RECOMMENDATION 2**: Whether or not you use [Throwable](https://metacpan.org/pod/Throwable), you should use
Packit Service 3b7cb7
[Try::Tiny](https://metacpan.org/pod/Try::Tiny).
Packit Service 3b7cb7
Packit Service 3b7cb7
Exception::Class allows you to declare exception hierarchies in your modules
Packit Service 3b7cb7
in a "Java-esque" manner.
Packit Service 3b7cb7
Packit Service 3b7cb7
It features a simple interface allowing programmers to 'declare' exception
Packit Service 3b7cb7
classes at compile time. It also has a base exception class,
Packit Service 3b7cb7
[Exception::Class::Base](https://metacpan.org/pod/Exception::Class::Base), that can be easily extended.
Packit Service 3b7cb7
Packit Service 3b7cb7
It is designed to make structured exception handling simpler and better by
Packit Service 3b7cb7
encouraging people to use hierarchies of exceptions in their applications, as
Packit Service 3b7cb7
opposed to a single catch-all exception class.
Packit Service 3b7cb7
Packit Service 3b7cb7
This module does not implement any try/catch syntax. Please see the "OTHER
Packit Service 3b7cb7
EXCEPTION MODULES (try/catch syntax)" section for more information on how to
Packit Service 3b7cb7
get this syntax.
Packit Service 3b7cb7
Packit Service 3b7cb7
You will also want to look at the documentation for [Exception::Class::Base](https://metacpan.org/pod/Exception::Class::Base),
Packit Service 3b7cb7
which is the default base class for all exception objects created by this
Packit Service 3b7cb7
module.
Packit Service 3b7cb7
Packit Service 3b7cb7
# DECLARING EXCEPTION CLASSES
Packit Service 3b7cb7
Packit Service 3b7cb7
Importing `Exception::Class` allows you to automagically create
Packit Service 3b7cb7
[Exception::Class::Base](https://metacpan.org/pod/Exception::Class::Base) subclasses. You can also create subclasses via the
Packit Service 3b7cb7
traditional means of defining your own subclass with `@ISA`.  These two
Packit Service 3b7cb7
methods may be easily combined, so that you could subclass an exception class
Packit Service 3b7cb7
defined via the automagic import, if you desired this.
Packit Service 3b7cb7
Packit Service 3b7cb7
The syntax for the magic declarations is as follows:
Packit Service 3b7cb7
Packit Service 3b7cb7
    'MANDATORY CLASS NAME' => \%optional_hashref
Packit Service 3b7cb7
Packit Service 3b7cb7
The hashref may contain the following options:
Packit Service 3b7cb7
Packit Service 3b7cb7
- isa
Packit Service 3b7cb7
Packit Service 3b7cb7
    This is the class's parent class. If this isn't provided then the class name
Packit Service 3b7cb7
    in `$Exception::Class::BASE_EXC_CLASS` is assumed to be the parent (see
Packit Service 3b7cb7
    below).
Packit Service 3b7cb7
Packit Service 3b7cb7
    This parameter lets you create arbitrarily deep class hierarchies.  This can
Packit Service 3b7cb7
    be any other [Exception::Class::Base](https://metacpan.org/pod/Exception::Class::Base) subclass in your declaration _or_ a
Packit Service 3b7cb7
    subclass loaded from a module.
Packit Service 3b7cb7
Packit Service 3b7cb7
    To change the default exception class you will need to change the value of
Packit Service 3b7cb7
    `$Exception::Class::BASE_EXC_CLASS` _before_ calling `import`. To do this
Packit Service 3b7cb7
    simply do something like this:
Packit Service 3b7cb7
Packit Service 3b7cb7
        BEGIN { $Exception::Class::BASE_EXC_CLASS = 'SomeExceptionClass'; }
Packit Service 3b7cb7
Packit Service 3b7cb7
    If anyone can come up with a more elegant way to do this please let me know.
Packit Service 3b7cb7
Packit Service 3b7cb7
    CAVEAT: If you want to automagically subclass an [Exception::Class::Base](https://metacpan.org/pod/Exception::Class::Base)
Packit Service 3b7cb7
    subclass loaded from a file, then you _must_ compile the class (via use or
Packit Service 3b7cb7
    require or some other magic) _before_ you import `Exception::Class` or
Packit Service 3b7cb7
    you'll get a compile time error.
Packit Service 3b7cb7
Packit Service 3b7cb7
- fields
Packit Service 3b7cb7
Packit Service 3b7cb7
    This allows you to define additional attributes for your exception class. Any
Packit Service 3b7cb7
    field you define can be passed to the `throw` or `new` methods as additional
Packit Service 3b7cb7
    parameters for the constructor. In addition, your exception object will have
Packit Service 3b7cb7
    an accessor method for the fields you define.
Packit Service 3b7cb7
Packit Service 3b7cb7
    This parameter can be either a scalar (for a single field) or an array
Packit Service 3b7cb7
    reference if you need to define multiple fields.
Packit Service 3b7cb7
Packit Service 3b7cb7
    Fields will be inherited by subclasses.
Packit Service 3b7cb7
Packit Service 3b7cb7
- alias
Packit Service 3b7cb7
Packit Service 3b7cb7
    Specifying an alias causes this class to create a subroutine of the specified
Packit Service 3b7cb7
    name in the _caller's_ namespace. Calling this subroutine is equivalent to
Packit Service 3b7cb7
    calling `<class>->throw(@_)` for the given exception class.
Packit Service 3b7cb7
Packit Service 3b7cb7
    Besides convenience, using aliases also allows for additional compile time
Packit Service 3b7cb7
    checking. If the alias is called _without parentheses_, as in `throw_fields
Packit Service 3b7cb7
    "an error occurred"`, then Perl checks for the existence of the
Packit Service 3b7cb7
    `throw_fields` subroutine at compile time. If instead you do `ExceptionWithFields->throw(...)`, then Perl checks the class name at
Packit Service 3b7cb7
    runtime, meaning that typos may sneak through.
Packit Service 3b7cb7
Packit Service 3b7cb7
- description
Packit Service 3b7cb7
Packit Service 3b7cb7
    Each exception class has a description method that returns a fixed
Packit Service 3b7cb7
    string. This should describe the exception _class_ (as opposed to any
Packit Service 3b7cb7
    particular exception object). This may be useful for debugging if you start
Packit Service 3b7cb7
    catching exceptions you weren't expecting (particularly if someone forgot to
Packit Service 3b7cb7
    document them) and you don't understand the error messages.
Packit Service 3b7cb7
Packit Service 3b7cb7
The `Exception::Class` magic attempts to detect circular class hierarchies
Packit Service 3b7cb7
and will die if it finds one. It also detects missing links in a chain, for
Packit Service 3b7cb7
example if you declare Bar to be a subclass of Foo and never declare Foo.
Packit Service 3b7cb7
Packit Service 3b7cb7
# [Try::Tiny](https://metacpan.org/pod/Try::Tiny)
Packit Service 3b7cb7
Packit Service 3b7cb7
If you are interested in adding try/catch/finally syntactic sugar to your code
Packit Service 3b7cb7
then I recommend you check out [Try::Tiny](https://metacpan.org/pod/Try::Tiny). This is a great module that helps
Packit Service 3b7cb7
you ignore some of the weirdness with `eval` and `$@`. Here's an example of
Packit Service 3b7cb7
how the two modules work together:
Packit Service 3b7cb7
Packit Service 3b7cb7
    use Exception::Class ( 'My::Exception' );
Packit Service 3b7cb7
    use Scalar::Util qw( blessed );
Packit Service 3b7cb7
    use Try::Tiny;
Packit Service 3b7cb7
Packit Service 3b7cb7
    try {
Packit Service 3b7cb7
        might_throw();
Packit Service 3b7cb7
    }
Packit Service 3b7cb7
    catch {
Packit Service 3b7cb7
        if ( blessed $_ && $_->isa('My::Exception') ) {
Packit Service 3b7cb7
            handle_it();
Packit Service 3b7cb7
        }
Packit Service 3b7cb7
        else {
Packit Service 3b7cb7
            die $_;
Packit Service 3b7cb7
        }
Packit Service 3b7cb7
    };
Packit Service 3b7cb7
Packit Service 3b7cb7
Note that you **cannot** use `Exception::Class->caught` with [Try::Tiny](https://metacpan.org/pod/Try::Tiny).
Packit Service 3b7cb7
Packit Service 3b7cb7
# Catching Exceptions Without [Try::Tiny](https://metacpan.org/pod/Try::Tiny)
Packit Service 3b7cb7
Packit Service 3b7cb7
`Exception::Class` provides some syntactic sugar for catching exceptions in a
Packit Service 3b7cb7
safe manner:
Packit Service 3b7cb7
Packit Service 3b7cb7
    eval {...};
Packit Service 3b7cb7
Packit Service 3b7cb7
    if ( my $e = Exception::Class->caught('My::Error') ) {
Packit Service 3b7cb7
        cleanup();
Packit Service 3b7cb7
        do_something_with_exception($e);
Packit Service 3b7cb7
    }
Packit Service 3b7cb7
Packit Service 3b7cb7
The `caught` method takes a class name and returns an exception object if the
Packit Service 3b7cb7
last thrown exception is of the given class, or a subclass of that class. If
Packit Service 3b7cb7
it is not given any arguments, it simply returns `$@`.
Packit Service 3b7cb7
Packit Service 3b7cb7
You should **always** make a copy of the exception object, rather than using
Packit Service 3b7cb7
`$@` directly. This is necessary because if your `cleanup` function uses
Packit Service 3b7cb7
`eval`, or calls something which uses it, then `$@` is overwritten. Copying
Packit Service 3b7cb7
the exception preserves it for the call to `do_something_with_exception`.
Packit Service 3b7cb7
Packit Service 3b7cb7
Exception objects also provide a caught method so you can write:
Packit Service 3b7cb7
Packit Service 3b7cb7
    if ( my $e = My::Error->caught ) {
Packit Service 3b7cb7
        cleanup();
Packit Service 3b7cb7
        do_something_with_exception($e);
Packit Service 3b7cb7
    }
Packit Service 3b7cb7
Packit Service 3b7cb7
## Uncatchable Exceptions
Packit Service 3b7cb7
Packit Service 3b7cb7
Internally, the `caught` method will call `isa` on the exception object. You
Packit Service 3b7cb7
could make an exception "uncatchable" by overriding `isa` in that class like
Packit Service 3b7cb7
this:
Packit Service 3b7cb7
Packit Service 3b7cb7
    package Exception::Uncatchable;
Packit Service 3b7cb7
Packit Service 3b7cb7
    sub isa { shift->rethrow }
Packit Service 3b7cb7
Packit Service 3b7cb7
Of course, this only works if you always call `Exception::Class->caught`
Packit Service 3b7cb7
after an `eval`.
Packit Service 3b7cb7
Packit Service 3b7cb7
# USAGE RECOMMENDATION
Packit Service 3b7cb7
Packit Service 3b7cb7
If you're creating a complex system that throws lots of different types of
Packit Service 3b7cb7
exceptions, consider putting all the exception declarations in one place. For
Packit Service 3b7cb7
an app called Foo you might make a `Foo::Exceptions` module and use that in
Packit Service 3b7cb7
all your code. This module could just contain the code to make
Packit Service 3b7cb7
`Exception::Class` do its automagic class creation. Doing this allows you to
Packit Service 3b7cb7
more easily see what exceptions you have, and makes it easier to keep track of
Packit Service 3b7cb7
them.
Packit Service 3b7cb7
Packit Service 3b7cb7
This might look something like this:
Packit Service 3b7cb7
Packit Service 3b7cb7
    package Foo::Bar::Exceptions;
Packit Service 3b7cb7
Packit Service 3b7cb7
    use Exception::Class (
Packit Service 3b7cb7
        Foo::Bar::Exception::Senses =>
Packit Service 3b7cb7
            { description => 'sense-related exception' },
Packit Service 3b7cb7
Packit Service 3b7cb7
        Foo::Bar::Exception::Smell => {
Packit Service 3b7cb7
            isa         => 'Foo::Bar::Exception::Senses',
Packit Service 3b7cb7
            fields      => 'odor',
Packit Service 3b7cb7
            description => 'stinky!'
Packit Service 3b7cb7
        },
Packit Service 3b7cb7
Packit Service 3b7cb7
        Foo::Bar::Exception::Taste => {
Packit Service 3b7cb7
            isa         => 'Foo::Bar::Exception::Senses',
Packit Service 3b7cb7
            fields      => [ 'taste', 'bitterness' ],
Packit Service 3b7cb7
            description => 'like, gag me with a spoon!'
Packit Service 3b7cb7
        },
Packit Service 3b7cb7
Packit Service 3b7cb7
        ...
Packit Service 3b7cb7
    );
Packit Service 3b7cb7
Packit Service 3b7cb7
You may want to create a real module to subclass [Exception::Class::Base](https://metacpan.org/pod/Exception::Class::Base) as
Packit Service 3b7cb7
well, particularly if you want your exceptions to have more methods.
Packit Service 3b7cb7
Packit Service 3b7cb7
## Subclassing Exception::Class::Base
Packit Service 3b7cb7
Packit Service 3b7cb7
As part of your usage of `Exception::Class`, you may want to create your own
Packit Service 3b7cb7
base exception class which subclasses [Exception::Class::Base](https://metacpan.org/pod/Exception::Class::Base). You should
Packit Service 3b7cb7
feel free to subclass any of the methods documented above. For example, you
Packit Service 3b7cb7
may want to subclass `new` to add additional information to your exception
Packit Service 3b7cb7
objects.
Packit Service 3b7cb7
Packit Service 3b7cb7
# Exception::Class FUNCTIONS
Packit Service 3b7cb7
Packit Service 3b7cb7
The `Exception::Class` method offers one function, `Classes`, which is not
Packit Service 3b7cb7
exported. This method returns a list of the classes that have been created by
Packit Service 3b7cb7
calling the `Exception::Class` `import` method.  Note that this is _all_
Packit Service 3b7cb7
the subclasses that have been created, so it may include subclasses created by
Packit Service 3b7cb7
things like CPAN modules, etc. Also note that if you simply define a subclass
Packit Service 3b7cb7
via the normal Perl method of setting `@ISA` or `use base`, then your
Packit Service 3b7cb7
subclass will not be included.
Packit Service 3b7cb7
Packit Service 3b7cb7
# SUPPORT
Packit Service 3b7cb7
Packit Service 3b7cb7
Bugs may be submitted at [https://github.com/houseabsolute/Exception-Class/issues](https://github.com/houseabsolute/Exception-Class/issues).
Packit Service 3b7cb7
Packit Service 3b7cb7
I am also usually active on IRC as 'autarch' on `irc://irc.perl.org`.
Packit Service 3b7cb7
Packit Service 3b7cb7
# SOURCE
Packit Service 3b7cb7
Packit Service 3b7cb7
The source code repository for Exception-Class can be found at [https://github.com/houseabsolute/Exception-Class](https://github.com/houseabsolute/Exception-Class).
Packit Service 3b7cb7
Packit Service 3b7cb7
# DONATIONS
Packit Service 3b7cb7
Packit Service 3b7cb7
If you'd like to thank me for the work I've done on this module, please
Packit Service 3b7cb7
consider making a "donation" to me via PayPal. I spend a lot of free time
Packit Service 3b7cb7
creating free software, and would appreciate any support you'd care to offer.
Packit Service 3b7cb7
Packit Service 3b7cb7
Please note that **I am not suggesting that you must do this** in order for me
Packit Service 3b7cb7
to continue working on this particular software. I will continue to do so,
Packit Service 3b7cb7
inasmuch as I have in the past, for as long as it interests me.
Packit Service 3b7cb7
Packit Service 3b7cb7
Similarly, a donation made in this way will probably not make me work on this
Packit Service 3b7cb7
software much more, unless I get so many donations that I can consider working
Packit Service 3b7cb7
on free software full time (let's all have a chuckle at that together).
Packit Service 3b7cb7
Packit Service 3b7cb7
To donate, log into PayPal and send money to autarch@urth.org, or use the
Packit Service 3b7cb7
button at [http://www.urth.org/~autarch/fs-donation.html](http://www.urth.org/~autarch/fs-donation.html).
Packit Service 3b7cb7
Packit Service 3b7cb7
# AUTHOR
Packit Service 3b7cb7
Packit Service 3b7cb7
Dave Rolsky <autarch@urth.org>
Packit Service 3b7cb7
Packit Service 3b7cb7
# CONTRIBUTORS
Packit Service 3b7cb7
Packit Service 3b7cb7
- Alexander Batyrshin <0x62ash@gmail.com>
Packit Service 3b7cb7
- Leon Timmermans <fawaka@gmail.com>
Packit Service 3b7cb7
- Ricardo Signes <rjbs@cpan.org>
Packit Service 3b7cb7
Packit Service 3b7cb7
# COPYRIGHT AND LICENSE
Packit Service 3b7cb7
Packit Service 3b7cb7
This software is copyright (c) 2017 by Dave Rolsky.
Packit Service 3b7cb7
Packit Service 3b7cb7
This is free software; you can redistribute it and/or modify it under
Packit Service 3b7cb7
the same terms as the Perl 5 programming language system itself.
Packit Service 3b7cb7
Packit Service 3b7cb7
The full text of the license can be found in the
Packit Service 3b7cb7
`LICENSE` file included with this distribution.