NAME
    Exception::Base - Lightweight exceptions

SYNOPSIS
      # Use module and create needed exceptions
      use Exception::Base
         'Exception::Runtime',              # create new module
         'Exception::System',               # load existing module
         'Exception::IO',          => {
             isa => 'Exception::System' },  # create new based on existing
         'Exception::FileNotFound' => {
             isa => 'Exception::IO',        # create new based on previous
             message => 'File not found',   # override default message
             has => [ 'filename' ],         # define new rw attribute
             stringify_attributes => [ 'message', 'filename' ],
         };                                 # output message and filename

      # eval/$@ (fastest method)
      eval {
        open my $file, '/etc/passwd'
          or Exception::FileNotFound->throw(
                message=>'Something wrong',
                filename=>'/etc/passwd');
      };
      if ($@) {
        my $e = Exception::Base->catch;   # convert $@ into exception
        if ($e->isa('Exception::IO')) { warn "IO problem"; }
        elsif ($e->isa('Exception::Eval')) { warn "eval died"; }
        elsif ($e->isa('Exception::Runtime')) { warn "some runtime was caught"; }
        elsif ($e->with(value=>9)) { warn "something happened"; }
        elsif ($e->with(qr/^Error/)) { warn "some error based on regex"; }
        else { $e->throw; } # rethrow the exception
      }
      # alternative syntax for Perl 5.10
      if ($@) {
        given (my $e = Exception::Base->catch) {
          when ('Exception::IO') { warn "IO problem"; }
          when ('Exception::Eval') { warn "eval died"; }
          when ('Exception::Runtime') { warn "some runtime was caught"; }
          when ({value=>9}) { warn "something happened"; }
          when (qr/^Error/) { warn "some error based on regex"; }
          default { $e->throw; } # rethrow the exception
        }
      }

      # try/catch (15x slower)
      use Exception::Base ':all';   # import try/catch/throw
      try eval {
        open my $file, '/etc/passwd'
          or throw 'Exception::FileNotFound' =>
                        message=>'Something wrong',
                        filename=>'/etc/passwd';
      };
      if (catch my $e) {
        # $e is an exception object so no need to check if is blessed
        if ($e->isa('Exception::IO')) { warn "IO problem"; }
        elsif ($e->isa('Exception::Eval')) { warn "eval died"; }
        elsif ($e->isa('Exception::Runtime')) { warn "some runtime was caught"; }
        elsif ($e->with(value=>9)) { warn "something happened"; }
        elsif ($e->with(qr/^Error/)) { warn "some error based on regex"; }
        else { $e->throw; } # rethrow the exception
      }

      # $@ has to be recovered ASAP!
      eval { die "this die will be caught" };
      my $e = Exception::Base->catch;
      eval { die "this die will be ignored" };
      if ($e) {
         (...)
      }

      # try/catch can be separated with another eval
      try eval { die "this die will be caught" };
      do { eval { die "this die will be ignored" } };
      catch my $e;   # only first die is recovered

      # the exception can be thrown later
      my $e = Exception::Base->new;
      # (...)
      $e->throw;

      # try returns eval's value for scalar or array context
      $v = try eval { do_something_returning_scalar(); };
      @v = try [eval { do_something_returning_array(); }];

      # ignore our package in stack trace
      package My::Package;
      use Exception::Base '+ignore_package' => __PACKAGE__;

      # define new exception in separate module
      package Exception::My;
      use Exception::Base (__PACKAGE__) => {
          has => ['myattr'],
      };

      # run Perl with changed verbosity for debugging purposes
      $ perl -MException::Base=verbosity,4 script.pl

DESCRIPTION
    This class implements a fully OO exception mechanism similar to
    Exception::Class or Class::Throwable. It provides a simple interface
    allowing programmers to declare exception classes. These classes can be
    thrown and caught. Each uncaught exception prints full stack trace if
    the default verbosity is uppered for debugging purposes.

    The features of Exception::Base:

    * fast implementation of the exception class

    * fully OO without closures and source code filtering

    * does not mess with $SIG{__DIE__} and $SIG{__WARN__}

    * no external modules dependencies, requires core Perl modules only

    * implements error stack, the try/catch blocks can be nested

    * the default behaviour of exception class can be changed globally or
      just for the thrown exception

    * matching the exception by class, message or other attributes

    * matching with string, regex or closure function

    * creating automatically the derived exception classes ("use" interface)

    * easly expendable, see Exception::System class for example

    * prints just an error message or dumps full stack trace

    * can propagate (rethrow) an exception

IMPORTS
    use Exception::Base 'catch', 'try', 'throw';
        Exports the catch, try and throw functions to the caller namespace.

          use Exception::Base qw< catch try throw >;
          try eval { throw 'Exception::Base'; };
          if (catch my $e) { warn "$e"; }

    use Exception::Base ':all';
        Exports all available symbols to the caller namespace (catch, try
        and throw).

    use Exception::Base '*attribute*' => *value*;
        Changes the default value for *attribute*. If the *attribute* name
        has no special prefix, its default value is replaced with a new
        *value*.

          use Exception::Base verbosity => 4;

        If the *attribute* name starts with "+" or "-" then the new *value*
        is based on previous value:

        *   If the original *value* was a reference to array, the new
            *value* can be included or removed from original array. Use
            array reference if you need to add or remove more than one
            element.

              use Exception::Base
                  "+ignore_packages" => [ __PACKAGE__, qr/^Moose::/ ],
                  "-ignore_class" => "My::Good::Class";

        *   If the original *value* was a number, it will be incremeted or
            decremented by the new *value*.

              use Exception::Base "+ignore_level" => 1;

        *   If the original *value* was a string, the new *value* will be
            included.

              use Exception::Base "+message" => ": The incuded message";

    use Exception::Base '*Exception*', ...;
        Loads additional exception class module. If the module is not
        available, creates the exception class automatically at compile
        time. The newly created class will be based on Exception::Base
        class.

          use Exception::Base qw< Exception::Custom Exception::SomethingWrong >;
          Exception::Custom->throw;

    use Exception::Base '*Exception*' => { isa => *BaseException*, version
    => *version*, ... };
        Loads additional exception class module. If the module's version is
        lower than given parameter or the module can't be loaded, creates
        the exception class automatically at compile time. The newly created
        class will be based on given class and has the given $VERSION
        variable.

        isa The newly created class will be based on given class.

        version
            The class will be created only if the module's version is lower
            than given parameter and will have the version given in the
            argument.

        has The class will contain new rw attibute (if parameter is a
            string) or attributes (if parameter is a reference to array of
            strings).

        message
        verbosity
        max_arg_len
        max_arg_nums
        max_eval_len
        *other attribute having default property*
            The class will have the default property for the given
            attribute.

          use Exception::Base
            'try', 'catch',
            'Exception::IO',
            'Exception::FileNotFound' => { isa => 'Exception::IO',
                                           has => [ 'filename' ] },
            'Exception::My' => { version => 0.2 },
            'Exception::WithDefault' => { message => 'Default message' };
          try eval { Exception::FileNotFound->throw( filename=>"/foo/bar" ); };
          if (catch my $e) {
            if ($e->isa('Exception::IO')) { warn "can be also FileNotFound"; }
            if ($e->isa('Exception::My')) { print $e->VERSION; }
          }

    no Exception::Base 'catch', 'try', 'throw';
    no Exception::Base ':all';
    no Exception::Base;
        Unexports the catch, try and throw functions from the caller
        namespace.

          use Exception::Base ':all', 'Exception::FileNotFound';
          try eval { Exception::FileNotFound->throw; };  # ok
          no Exception::Base;
          try eval { Exception::FileNotFound->throw; };  # syntax error

CONSTANTS
    ATTRS
        Declaration of class attributes as reference to hash.

        The attributes are listed as *name* => {*properties*}, where
        *properties* is a list of attribute properties:

        is  Can be 'rw' for read-write attributes or 'ro' for read-only
            attributes. The attribute is read-only and does not have an
            accessor created if 'is' property is missed.

        default
            Optional property with the default value if the attribute value
            is not defined.

        The read-write attributes can be set with new constructor. Read-only
        attributes and unknown attributes are ignored.

        The constant have to be defined in derivered class if it brings
        additional attributes.

          package Exception::My;
          our $VERSION = 0.01;
          use base 'Exception::Base';

          # Define new class attributes
          use constant ATTRS => {
            %{Exception::Base->ATTRS},       # base's attributes have to be first
            readonly  => { is=>'ro' },                   # new ro attribute
            readwrite => { is=>'rw', default=>'blah' },  # new rw attribute
          };

          package main;
          use Exception::Base ':all';
          try eval {
            throw 'Exception::My' => readwrite=>2;
          };
          if (catch my $e) {
            print $e->{readwrite};                # = 2
            print $e->{defaults}->{readwrite};    # = "blah"
          }

    RE_NUM_INT
        Represents regexp for numeric integer value.

ATTRIBUTES
    Class attributes are implemented as values of blessed hash. The
    attributes are also available as accessors methods.

    message (rw, default: 'Unknown exception')
        Contains the message of the exception. It is the part of the string
        representing the exception object.

          eval { Exception::Base->throw( message=>"Message" ); };
          print $@->{message} if $@;

    value (rw, default: 0)
        Contains the value which represents numeric value of the exception
        object in numeric context.

          eval { Exception::Base->throw( value=>2 ); };
          print "Error 2" if $@ == 2;

    verbosity (rw, default: 2)
        Contains the verbosity level of the exception object. It allows to
        change the string representing the exception object. There are
        following levels of verbosity:

        * Empty string

        1
           Message

        2
           Message at %s line %d.

          The same as the standard output of die() function. This is the
          default option.

        3
           Class: Message at %s line %d
                   %c_ = %s::%s() called in package %s at %s line %d
                   ...propagated in package %s at %s line %d.
           ...

          The output contains full trace of error stack without first
          ignore_level lines and those packages which are listed in
          ignore_package and ignore_class settings.

        4 The output contains full trace of error stack. In this case the
          ignore_level, ignore_package and ignore_class settings are meaning
          only for first line of exception's message.

        If the verbosity is undef, then the default verbosity for exception
        objects is used.

        If the verbosity set with constructor (new or throw) is lower than
        3, the full stack trace won't be collected.

        If the verbosity is lower than 2, the full system data (time, pid,
        tid, uid, euid, gid, egid) won't be collected.

        This setting can be changed with import interface.

          use Exception::Base verbosity => 4;

        It can be also changed for Perl interpreter instance, i.e. for
        debugging purposes.

          sh$ perl -MException::Base=verbosity,4 script.pl

    ignore_package (rw)
        Contains the name (scalar or regexp) or names (as references array)
        of packages which are ignored in error stack trace. It is useful if
        some package throws an exception but this module shouldn't be listed
        in stack trace.

          package My::Package;
          use Exception::Base;
          sub my_function {
            do_something() or throw Exception::Base ignore_package=>__PACKAGE__;
            throw Exception::Base ignore_package => [ "My", qr/^My::Modules::/ ];
          }

        This setting can be changed with import interface.

          use Exception::Base ignore_package => __PACKAGE__;

    ignore_class (rw)
        Contains the name (scalar) or names (as references array) of
        packages which are base classes for ignored packages in error stack
        trace. It means that some packages will be ignored even the derived
        class was called.

          package My::Package;
          use Exception::Base;
          Exception::Base->throw( ignore_class => "My::Base" );

        This setting can be changed with import interface.

          use Exception::Base ignore_class => "My::Base";

    ignore_level (rw)
        Contains the number of level on stack trace to ignore. It is useful
        if some package throws an exception but this module shouldn't be
        listed in stack trace. It can be used with or without
        *ignore_package* attribute.

          # Convert warning into exception. The signal handler ignores itself.
          use Exception::Base 'Exception::My::Warning';
          $SIG{__WARN__} = sub {
            Exception::My::Warning->throw( message => $_[0], ignore_level => 1 );
          };

    time (ro)
        Contains the timestamp of the thrown exception. Collected if the
        verbosity on throwing exception was greater than 1.

          eval { Exception::Base->throw( message=>"Message" ); };
          print scalar localtime $@->{time};

    pid (ro)
        Contains the PID of the Perl process at time of thrown exception.
        Collected if the verbosity on throwing exception was greater than 1.

          eval { Exception::Base->throw( message=>"Message" ); };
          kill 10, $@->{pid};

    tid (ro)
        Constains the tid of the thread or undef if threads are not used.
        Collected if the verbosity on throwing exception was greater than 1.

    uid (ro)
    euid (ro)
    gid (ro)
    egid (ro)
        Contains the real and effective uid and gid of the Perl process at
        time of thrown exception. Collected if the verbosity on throwing
        exception was greater than 1.

    caller_stack (ro)
        Contains the error stack as array of array with informations about
        caller functions. The first 8 elements of the array's row are the
        same as first 8 elements of the output of caller function. Further
        elements are optional and are the arguments of called function.
        Collected if the verbosity on throwing exception was greater than 1.
        Contains only the first element of caller stack if the verbosity was
        lower than 3.

          eval { Exception::Base->throw( message=>"Message" ); };
          ($package, $filename, $line, $subroutine, $hasargs, $wantarray,
          $evaltext, $is_require, @args) = $@->{caller_stack}->[0];

    propagated_stack (ro)
        Contains the array of array which is used for generating
        "...propagated at" message. The elements of the array's row are the
        same as first 3 elements of the output of caller function.

    max_arg_len (rw, default: 64)
        Contains the maximal length of argument for functions in backtrace
        output. Zero means no limit for length.

          sub a { Exception::Base->throw( max_arg_len=>5 ) }
          a("123456789");

    max_arg_nums (rw, default: 8)
        Contains the maximal number of arguments for functions in backtrace
        output. Zero means no limit for arguments.

          sub a { Exception::Base->throw( max_arg_nums=>1 ) }
          a(1,2,3);

    max_eval_len (rw, default: 0)
        Contains the maximal length of eval strings in backtrace output.
        Zero means no limit for length.

          eval "Exception->throw( max_eval_len=>10 )";
          print "$@";

    defaults
        Meta-attribute contains the list of default values.

          my $e = Exception::Base->new;
          print defined $e->{verbosity}
            ? $e->{verbosity}
            : $e->{defaults}->{verbosity};

    default_attribute (default: 'message')
        Meta-attribute contains the name of the default attribute. This
        attribute will be set for one argument throw method. This attribute
        has meaning for derived classes.

          use Exception::Base 'Exception::My' => {
              has => 'myattr',
              default_attribute => 'myattr',
          };

          eval { Exception::My->throw("string") };
          print $@->myattr;    # "string"

    numeric_attribute (default: 'value')
        Meta-attribute contains the name of the attribute which contains
        numeric value of exception object. This attribute will be used for
        representing exception in numeric context.

          use Exception::Base 'Exception::My' => {
              has => 'myattr',
              numeric_attribute => 'myattr',
          };

          eval { Exception::My->throw(myattr=>123) };
          print 0 + $@;    # 123

    eval_attribute (default: 'message')
        Meta-attribute contains the name of the attribute which is filled if
        error stack is empty. This attribute will contain value of $@
        variable. This attribute has meaning for derived classes.

          use Exception::Base 'Exception::My' => {
              has => 'myattr',
              eval_attribute => 'myattr'
          };

          eval { die "string" };
          print $@->myattr;    # "string"

    stringify_attributes (default: ['message'])
        Meta-attribute contains the array of names of attributes with
        defined value which are joined to the string returned by stringify
        method. If none of attributes are defined, the string is created
        from the first default value of attributes listed in the opposite
        order.

          use Exception::Base 'Exception::My' => {
              has => 'myattr',
              myattr => 'default',
              stringify_attributes => ['message', 'myattr'],
          };

          eval { Exception::My->throw( message=>"string", myattr=>"foo" ) };
          print $@->myattr;    # "string: foo"

          eval { Exception::My->throw() };
          print $@->myattr;    # "default"

OVERLOADS
    Boolean context
        True value.

          eval { Exception::Base->throw( message=>"Message", value=>123 ) };
          if ($@) {
             # the exception object is always true
          }

    Numeric context
        Content of attribute pointed by numeric_attribute attribute. See
        numerify method.

          eval { Exception::Base->throw( message=>"Message", value=>123 ) };
          print 0+$@;           # 123

    String context
        Content of attribute which is combined from stringify_attributes
        attributes with additional informations, depended on verbosity
        setting. See stringify method.

          eval { Exception::Base->throw( message=>"Message", value=>123 ) };
          print "$@";           # "Message at -e line 1.\n"

    "~~"
        Smart matching operator. See matches method.

          eval { Exception::Base->throw( message=>"Message", value=>123 ) };
          print $@ ~~ "Message";                          # 1
          print $@ ~~ qr/message/i;                       # 1
          print $@ ~~ ['Exception::Base'];                # 1
          print $@ ~~ 123;                                # 1
          print $@ ~~ {message=>"Message", value=>123};   # 1

CONSTRUCTORS
    new([%*args*])
        Creates the exception object, which can be thrown later. The system
        data attributes like time, pid, uid, gid, euid, egid are not filled.

        If the key of the argument is read-write attribute, this attribute
        will be filled. Otherwise, the argument will be ignored.

          $e = Exception::Base->new(
                   message=>"Houston, we have a problem",
                   unknown_attr => "BIG"
               );
          print $e->{message};

        The constructor reads the list of class attributes from ATTRS
        constant function and stores it in the internal cache for
        performance reason. The defaults values for the class are also
        stored in internal cache.

    throw([%*args*]])
        Creates the exception object and immediately throws it with die
        system function.

          open FILE, $file
            or Exception::Base->throw( message=>"Can not open file: $file" );

        The throw is also exported as a function.

          open FILE, $file
            or throw 'Exception::Base' => message=>"Can not open file: $file";

    The throw can be also used as a method.

METHODS
    throw([%*args*])
        Immediately throws exception object. It can be used for rethrowing
        existing exception object. Additional arguments will override the
        attributes in existing exception object.

          $e = Exception::Base->new;
          # (...)
          $e->throw( message=>"thrown exception with overriden message" );

          eval { Exception::Base->throw( message=>"Problem", value=>1 ) };
          $@->throw if $@->{value};

    throw(*message*, [%*args*])
        If the number of *args* list for arguments is odd, the first
        argument is a message. This message can be overriden by message from
        *args* list.

          Exception::Base->throw( "Problem", message=>"More important" );
          eval { die "Bum!" };
          Exception::Base->throw( $@, message=>"New message" );

    *CLASS*->throw($*exception*, [%*args*])
        Immediately rethrows an existing exception object as an other
        exception class.

          eval { open $f, "w", "/etc/passwd" or Exception::System->throw };
          # convert Exception::System into Exception::Base
          Exception::Base->throw($@);

    stringify([$*verbosity*[, $*message*]])
        Returns the string representation of exception object. It is called
        automatically if the exception object is used in string scalar
        context. The method can be used explicity and then the verbosity
        level can be used.

          eval { Exception::Base->throw; };
          $@->{verbosity} = 1;
          print "$@";
          print $@->stringify(4) if $VERY_VERBOSE;

        It also replaces any message stored in object with the *message*
        argument if it exists. If message argument is an empty string, the
        default message is used.

          eval { Exception::Base->throw( "Message" ); };
          print $@->stringify(1);               # "Message"
          print $@->stringify(1, "Overrided");  # "Overrided"
          print $@->stringify(1, "");           # "Unknown exception"

    numerify
        Returns the numeric representation of exception object. It is called
        automatically if the exception object is used in numeric scalar
        context. The method can be used explicity.

          eval { Exception::Base->throw( value => 42 ); };
          print 0+$@;           # 42
          print $@->numerify;   # 42

    matches(*that*)
        Checks if the exception object matches the given argument. It is
        somewhat similar to the with method but it takes only one argument.
        The matches method overloads ~~ smart matching operator, so it can
        be used with given keyword.

          given ($e = Exception::Base->new( message=>"Message", value=>123 )) {
            when( "Message" ) { ... }                             # matches
            when( qr/message/i ) { ... }                          # matches
            when( ["Exception::Base"] ) { ... }                   # matches
            when( ["Exception::Foo", "Exception::Bar"] ) { ... }  # doesn't
            when( { message=>"Message" } ) { ... }                # matches
            when( { value=>123 } ) { ... }                        # matches
            when( { message=>"Message", value=>45 } ) { ... }     # doesn't
            when( { uid=>0 } ) { ... }  # matches if runs with root privileges
          }

        If the argument is a reference to array, it is checked if the object
        is a given class.

          use Exception::Base
            'Exception::Simple',
            'Exception::Complex' => { isa => 'Exception::Simple };
          eval { Exception::Complex->throw() };
          print $@ ~~ ['Exception::Base'];                        # matches
          print $@ ~~ ['Exception::Simple', 'Exception::Other'];  # matches
          print $@ ~~ ['NullObject'];                             # doesn't

        If the argument is a reference to hash, attributes of the exception
        object is matched.

          eval { Exception::Base->throw( message=>"Message", value=>123 ) };
          print $@ ~~ { message=>"Message" };             # matches
          print $@ ~~ { value=>123 };                     # matches
          print $@ ~~ { message=>"Message", value=>45 };  # doesn't

        If the argument is a single string, regexp or code reference or is
        undefined, the default attribute of the exception object is matched
        (usually it is a "message" attribute).

          eval { Exception::Base->throw( message=>"Message" ) };
          print $@ ~~ "Message";                          # matches
          print $@ ~~ qr/Message/;                        # matches
          print $@ ~~ qr/[0-9]/;                          # doesn't
          print $@ ~~ sub{/Message/};                     # matches
          print $@ ~~ sub{0};                             # doesn't
          print $@ ~~ undef;                              # doesn't

        If argument is a numeric value, the argument matches if value
        attribute matches.

          eval { Exception::Base->throw( value=>123, message=>456 ) };
          print $@ ~~ 123;                                # matches
          print $@ ~~ 456;                                # doesn't

    with(*condition*)
        Checks if the exception object matches the given condition. If the
        first argument is single value, the message combined from
        stringify_attributes attributes is matched. If the argument is a
        part of hash, an attribute of the exception object is matched. The
        with method returns true value if all its arguments match.

          eval { Exception::Base->new( message=>"Message", value=>123 ) };
          print $@->with( "Message" );                    # matches
          print $@->with( value=>123 );                   # matches
          print $@->with( "Message", value=>45 );         # doesn't
          print $@->with( uid=>0 );               # matches if root
          print $@->with( message=>"Message" );           # matches

        The argument (for message or attributes) can be simple string or
        code reference or regexp.

          eval { Exception::Base->new( message=>"Message" ) };
          print $@->with( "Message" );                    # matches
          print $@->with( sub {/Message/} );              # matches
          print $@->with( qr/Message/ );                  # matches

        If argument is a numeric value, the argument matches if attribute
        pointed by numeric_attribute attribute matches.

          eval { Exception::Base->new( value=>123, message=>456 ) };
          print $@->with( 123 );                          # matches
          print $@->with( 456 );                          # doesn't

        If argument is a reference to array, the argument matches if any of
        its element matches.

          eval { Exception::Base->new( message=>"Message", value=>123 ) };
          print $@->with( message=>["Not", 123, 45, "Message"] );  # matches
          print $@->with( value=>[123, 45], message=>"Not" );      # doesn't

        The with method matches for special keywords:

        -isa
            Matches if the object is a given class.

              eval { Exception::Base->new( message=>"Message" ) };
              print $@->with( -isa=>"Exception::Base" );                   # matches
              print $@->with( -isa=>["Some::Class", "Exception::Base"] );  # matches

        -has
            Matches if the object has a given attribute.

              eval { Exception::Base->new( message=>"Message" ) };
              print $@->with( -has=>"Message" );              # matches

        -default
            Matches against the default attribute, usually the message
            attribute.

              eval { Exception::Base->new( message=>"Message" ) };
              print $@->with( -default=>"Message" );          # matches

    try(*eval*)
        The try method or function can be used with eval block as argument
        and then the eval's error is pushed into error stack and can be used
        with catch later. The $@ variable is replaced with empty string.

          try eval { Exception::Base->throw; };
          eval { die "another error messing with \$@ variable"; };
          catch my $e;

        The try returns the value of the argument in scalar context. If the
        argument is array reference, the try returns the value of the
        argument in array context.

          $v = Exception::Base->try( eval { 2 + 2; } ); # $v == 4
          @v = Exception::Base->try( [ eval { (1,2,3); }; ] ); # @v = (1,2,3)

        The try can be used as method or function.

          try 'Exception::Base' => eval {
            Exception::Base->throw( message=>"method" );
          };
          Exception::Base::try eval {
            Exception::Base->throw( message=>"function" );
          };
          Exception::Base->import( 'try' );
          try eval {
            Exception::Base->throw( message=>"imported function" );
          };

    *CLASS*->catch([$*variable*])
        The exception is popped from error stack and returned from method or
        written into the method argument.

          eval { Exception::Base->throw; };
          if ($@) {
              my $e = Exception::Base->catch;
              print $e->stringify(1);
          }

        If the error stack is empty, the catch method recovers $@ variable
        and replaces it with empty string to avoid endless loop. It allows
        to use catch method without previous try.

        If the popped value is not empty and does not contain the
        Exception::Base object, new exception object is created with class
        *CLASS* and its message is based on previous value with removed " at
        file line 123." string and the last end of line (LF).

          eval { die "Died\n"; };
          my $e = Exception::Base->catch;
          print ref $e;   # "Exception::Base"

        The method returns 1, if the exception object is caught, and returns
        0 otherwise.

          try eval { throw 'Exception::Base'; };
          if (catch my $e) {
            warn "Exception caught: " . ref $e;
          }

        If the method argument is missing, the method returns the exception
        object.

          eval { Exception::Base->throw; };
          my $e = Exception::Base->catch;

        The catch can be used as method or function. If it is used as
        function, then the *CLASS* is Exception::Base by default.

          try eval { throw 'Exception::Base' => message=>"method"; };
          Exception::Base->import( 'catch' );
          catch my $e;  # the same as Exception::Base->catch( my $e );
          print $e->stringify;

    PROPAGATE
        Checks the caller stack and fills the propagated_stack attribute. It
        is usually used if die system function was called without any
        arguments.

    package
        Returns the package name of the subroutine which thrown an
        exception.

    file
        Returns the file name of the subroutine which thrown an exception.

    line
        Returns the line number for file of the subroutine which thrown an
        exception.

    subroutine
        Returns the subroutine name which thrown an exception.

PRIVATE METHODS
    _collect_system_data
        Collects system data and fills the attributes of exception object.
        This method is called automatically if exception if thrown. It can
        be used by derived class.

          package Exception::Special;
          use base 'Exception::Base';
          use constant ATTRS => {
            %{Exception::Base->ATTRS},
            'special' => { is => 'ro' },
          };
          sub _collect_system_data {
            my $self = shift;
            $self->SUPER::_collect_system_data(@_);
            $self->{special} = get_special_value();
            return $self;
          }
          __PACKAGE__->_make_accessors;
          1;

        Method returns the reference to the self object.

    _make_accessors
        Creates accessors for each attribute. This static method should be
        called in each derived class which defines new attributes.

          package Exception::My;
          # (...)
          __PACKAGE__->_make_accessors;

    __stringify
        Method called by overload's q{""} operator. It have to be
        reimplemented in derived class if it has stringify method
        implemented.

    __numerify
        Method called by overload's 0+ operator. It have to be reimplemented
        in derived class if it has numerify method implemented.

SEE ALSO
    There are more implementation of exception objects available on CPAN.
    Please note that Perl has built-in implementation of pseudo-exceptions:

      eval { die { message => "Pseudo-exception", package => __PACKAGE__,
                   file => __FILE__, line => __LINE__ };
      };
      if ($@) {
        print $@->{message}, " at ", $@->{file}, " in line ", $@->{line}, ".\n";
      }

    The more complex implementation of exception mechanism provides more
    features.

    Error
        Complete implementation of try/catch/finally/otherwise mechanism.
        Uses nested closures with a lot of syntactic sugar. It is slightly
        faster than Exception::Base module for failure scenario and is much
        slower for success scenario. It doesn't provide a simple way to
        create user defined exceptions. It doesn't collect system data and
        stack trace on error.

    Exception::Class
        More perl-ish way to do OO exceptions. It is too heavy and too slow
        for failure scenario and slightly slower for success scenario. It
        requires non-core perl modules to work.

    Exception::Class::TryCatch
        Additional try/catch mechanism for Exception::Class. It is also slow
        as Exception::Base with try/catch mechanism for success scenario.

    Class::Throwable
        Elegant OO exceptions without try/catch mechanism. It might be
        missing some features found in Exception::Base and Exception::Class.

    Exceptions
        Not recommended. Abadoned. Modifies %SIG handlers.

    The Exception::Base does not depend on other modules like
    Exception::Class and it is more powerful than Class::Throwable. Also it
    does not use closures as Error and does not polute namespace as
    Exception::Class::TryCatch. It is also much faster than Exception::Class
    and Error.

    The Exception::Base is also a base class for enchanced classes:

    Exception::System
        The exception class for system or library calls which modifies $!
        variable.

    Exception::Died
        The exception class for eval blocks with simple "die" in perlfunc.
        It can also handle $SIG{__DIE__} hook and convert simple "die" in
        perlfunc into an exception object.

    Exception::Warning
        The exception class which handle $SIG{__WARN__} hook and convert
        simple "warn" in perlfunc into an exception object.

EXAMPLES
  New exception classes
    The Exception::Base module allows to create new exception classes easly.
    You can use import interface or base module to do it.

    The import interface allows to create new class with new read-write
    attributes.

      package Exception::Simple;
      use Exception::Base (__PACKAGE__) => {
        has => qw< reason method >,
        stringify_attributes => qw< message reason method >,
      };

    For more complex exceptions you can redefine ATTRS constant.

      package Exception::Complex;
      use base 'Exception::Base';
      use constant ATTRS => {
        %{ Exception::Base->ATTRS },     # SUPER::ATTRS
        hostname => { is => 'ro' },
        stringify_attributes => qw< hostname message >,
      };
      sub _collect_system_data {
        my $self = shift;
        my $hostname = `hostname`;
        chomp $hostname;
        $self->{hostname} = $hostname;
        return $self->SUPER::_collect_system_data(@_);
      }

PERFORMANCE
    There are two scenarios for "eval" block: success or failure. Success
    scenario should have no penalty on speed. Failure scenario is usually
    more complex to handle and can be significally slower.

    Any other code than simple "if ($@)" is really slow and shouldn't be
    used if speed is important. It means that Error and
    Exception::Class::TryCatch should be avoided as far as they are slow by
    design. The Exception::Class module doesn't use "if ($@)" syntax in its
    documentation so it was benchmarked with its default syntax, however it
    might be possible to convert it to simple "if ($@)".

    The Exception::Base module was benchmarked with other implementations
    for simple try/catch scenario. The results (Perl 5.10
    i686-linux-thread-multi) are following:

      -----------------------------------------------------------------------
      | Module                              | Success       | Failure       |
      -----------------------------------------------------------------------
      | eval/die string                     |      818638/s |      237975/s |
      -----------------------------------------------------------------------
      | eval/die object                     |      849686/s |      124853/s |
      -----------------------------------------------------------------------
      | Exception::Base eval/if             |      848593/s |        8356/s |
      -----------------------------------------------------------------------
      | Exception::Base try/catch           |       56639/s |        9218/s |
      -----------------------------------------------------------------------
      | Exception::Base eval/if verbosity=1 |      849180/s |       14899/s |
      -----------------------------------------------------------------------
      | Exception::Base try/catch verbos.=1 |       56986/s |       18232/s |
      -----------------------------------------------------------------------
      | Error                               |       88123/s |       19782/s |
      -----------------------------------------------------------------------
      | Class::Throwable                    |      844204/s |        7545/s |
      -----------------------------------------------------------------------
      | Exception::Class                    |      344124/s |        1311/s |
      -----------------------------------------------------------------------
      | Exception::Class::TryCatch          |      223822/s |        1270/s |
      -----------------------------------------------------------------------

    The Exception::Base module was written to be as fast as it is possible.
    It does not use internally i.e. accessor functions which are slower
    about 6 times than standard variables. It is slower than pure die/eval
    because it is uses OO mechanisms which are slow in Perl. It can be a
    litte faster if some features are disables, i.e. the stack trace and
    higher verbosity.

    You can find the benchmark script in this package distribution.

BUGS
    If you find the bug, please report it.

AUTHOR
    Piotr Roszatycki <dexter@debian.org>

LICENSE
    Copyright (C) 2007, 2008 by Piotr Roszatycki <dexter@debian.org>.

    This program is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.

    See <http://www.perl.com/perl/misc/Artistic.html>

