File Coverage

blib/lib/Exception/Base.pm
Criterion Covered Total %
statement 552 578 95.5
branch 347 408 85.0
condition 68 105 64.7
subroutine 48 48 100.0
pod 9 9 100.0
total 1024 1148 89.2


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -c
2              
3             package Exception::Base;
4              
5             =head1 NAME
6              
7             Exception::Base - Lightweight exceptions
8              
9             =head1 SYNOPSIS
10              
11             # Use module and create needed exceptions
12             use Exception::Base
13             'Exception::Runtime', # create new module
14             'Exception::System', # load existing module
15             'Exception::IO', => {
16             isa => 'Exception::System' }, # create new based on existing
17             'Exception::FileNotFound' => {
18             isa => 'Exception::IO', # create new based on previous
19             message => 'File not found', # override default message
20             has => [ 'filename' ], # define new rw attribute
21             string_attributes => [ 'message', 'filename' ],
22             }; # output message and filename
23              
24             # eval is used as "try" block
25             eval {
26             open my $file, '/etc/passwd'
27             or Exception::FileNotFound->throw(
28             message=>'Something wrong',
29             filename=>'/etc/passwd');
30             };
31             # syntax for Perl >= 5.10
32             use feature 'switch';
33             if ($@) {
34             given (my $e = Exception::Base->catch) {
35             when ($e->isa('Exception::IO')) { warn "IO problem"; }
36             when ($e->isa('Exception::Eval')) { warn "eval died"; }
37             when ($e->isa('Exception::Runtime')) { warn "some runtime was caught"; }
38             when ($e->matches({value=>9})) { warn "something happened"; }
39             when ($e->matches(qr/^Error/)) { warn "some error based on regex"; }
40             default { $e->throw; } # rethrow the exception
41             }
42             }
43             # standard syntax for older Perl
44             if ($@) {
45             my $e = Exception::Base->catch; # convert $@ into exception
46             if ($e->isa('Exception::IO')) { warn "IO problem"; }
47             elsif ($e->isa('Exception::Eval')) { warn "eval died"; }
48             elsif ($e->isa('Exception::Runtime')) { warn "some runtime was caught"; }
49             elsif ($e->matches({value=>9})) { warn "something happened"; }
50             elsif ($e->matches(qr/^Error/)) { warn "some error based on regex"; }
51             else { $e->throw; } # rethrow the exception
52             }
53              
54             # $@ has to be recovered ASAP!
55             eval { die "this die will be caught" };
56             my $e = Exception::Base->catch;
57             eval { die "this die will be ignored" };
58             if ($e) {
59             (...)
60             }
61              
62             # the exception can be thrown later
63             my $e = Exception::Base->new;
64             # (...)
65             $e->throw;
66              
67             # ignore our package in stack trace
68             package My::Package;
69             use Exception::Base '+ignore_package' => __PACKAGE__;
70              
71             # define new exception in separate module
72             package Exception::My;
73             use Exception::Base (__PACKAGE__) => {
74             has => ['myattr'],
75             };
76              
77             # run Perl with changed verbosity for debugging purposes
78             $ perl -MException::Base=verbosity,4 script.pl
79              
80             =head1 DESCRIPTION
81              
82             This class implements a fully OO exception mechanism similar to
83             L or L. It provides a simple interface
84             allowing programmers to declare exception classes. These classes can be
85             thrown and caught. Each uncaught exception prints full stack trace if the
86             default verbosity is increased for debugging purposes.
87              
88             The features of C:
89              
90             =over 2
91              
92             =item *
93              
94             fast implementation of the exception class
95              
96             =item *
97              
98             fully OO without closures and source code filtering
99              
100             =item *
101              
102             does not mess with C<$SIG{__DIE__}> and C<$SIG{__WARN__}>
103              
104             =item *
105              
106             no external run-time modules dependencies, requires core Perl modules only
107              
108             =item *
109              
110             the default behavior of exception class can be changed globally or just for
111             the thrown exception
112              
113             =item *
114              
115             matching the exception by class, message or other attributes
116              
117             =item *
118              
119             matching with string, regex or closure function
120              
121             =item *
122              
123             creating automatically the derived exception classes (L
124             interface)
125              
126             =item *
127              
128             easily expendable, see L class for example
129              
130             =item *
131              
132             prints just an error message or dumps full stack trace
133              
134             =item *
135              
136             can propagate (rethrow) an exception
137              
138             =item *
139              
140             can ignore some packages for stack trace output
141              
142             =item *
143              
144             some defaults (i.e. verbosity) can be different for different exceptions
145              
146             =back
147              
148             =for readme stop
149              
150             =cut
151              
152 1     1   3227 use 5.006;
  1         4  
153              
154 1     1   5 use strict;
  1         2  
  1         21  
155 1     1   19 use warnings;
  1         2  
  1         114  
156              
157             our $VERSION = '0.2501';
158              
159              
160             # Safe operations on symbol stash
161             BEGIN {
162 1     1   2 eval {
163 1         4 require Symbol;
164 1         5 Symbol::qualify_to_ref('Symbol::qualify_to_ref');
165             };
166 1 50       18 if (not $@) {
167 1         132 *_qualify_to_ref = \*Symbol::qualify_to_ref;
168             }
169             else {
170 1     1   5 *_qualify_to_ref = sub ($;) { no strict 'refs'; \*{ $_[0] } };
  1         2  
  1         58  
  0         0  
  0         0  
  0         0  
171             };
172             };
173              
174              
175             # Use weaken ref on stack if available
176             BEGIN {
177 1     1   3 eval {
178 1         5 require Scalar::Util;
179 1         3 my $ref = \1;
180 1         8 Scalar::Util::weaken($ref);
181             };
182 1 50       4 if (not $@) {
183 1         75 *_HAVE_SCALAR_UTIL_WEAKEN = sub () { !! 1 };
184             }
185             else {
186 0         0 *_HAVE_SCALAR_UTIL_WEAKEN = sub () { !! 0 };
187             };
188             };
189              
190              
191             BEGIN {
192 1     1   57 my %OVERLOADS = (fallback => 1);
193              
194             =head1 OVERLOADS
195              
196             =over
197              
198             =item Boolean context
199              
200             True value. See C method.
201              
202             eval { Exception::Base->throw( message=>"Message", value=>123 ) };
203             if ($@) {
204             # the exception object is always true
205             }
206              
207             =cut
208              
209 1         2 $OVERLOADS{'bool'} = 'to_bool';
210              
211             =item Numeric context
212              
213             Content of attribute pointed by C attribute. See
214             C method.
215              
216             eval { Exception::Base->throw( message=>"Message", value=>123 ) };
217             print 0+$@; # 123
218              
219             =cut
220              
221 1         2 $OVERLOADS{'0+'} = 'to_number';
222              
223             =item String context
224              
225             Content of attribute which is combined from C attributes
226             with additional information, depended on C setting. See
227             C method.
228              
229             eval { Exception::Base->throw( message=>"Message", value=>123 ) };
230             print "$@"; # "Message at -e line 1.\n"
231              
232             =cut
233              
234 1         2 $OVERLOADS{'""'} = 'to_string';
235              
236             =item "~~"
237              
238             Smart matching operator. See C method.
239              
240             eval { Exception::Base->throw( message=>"Message", value=>123 ) };
241             print "Message" ~~ $@; # 1
242             print qr/message/i ~~ $@; # 1
243             print ['Exception::Base'] ~~ $@; # 1
244             print 123 ~~ $@; # 1
245             print {message=>"Message", value=>123} ~~ $@; # 1
246              
247             Warning: The smart operator requires that the exception object is a second
248             argument.
249              
250             =back
251              
252             =cut
253              
254 1 50       5 $OVERLOADS{'~~'} = 'matches' if ($] >= 5.010);
255              
256 1     1   5 use overload;
  1         2  
  1         8  
257 1         4 overload->import(%OVERLOADS);
258             };
259              
260              
261             # Constant regexp for numerify value check
262 1     1   148 use constant _RE_NUM_INT => qr/^[+-]?\d+$/;
  1         2  
  1         466  
263              
264              
265             =head1 CONSTANTS
266              
267             =over
268              
269             =item ATTRS
270              
271             Declaration of class attributes as reference to hash.
272              
273             The attributes are listed as I => {I}, where I is a
274             list of attribute properties:
275              
276             =over
277              
278             =item is
279              
280             Can be 'rw' for read-write attributes or 'ro' for read-only attributes. The
281             attribute is read-only and does not have an accessor created if 'is' property
282             is missed.
283              
284             =item default
285              
286             Optional property with the default value if the attribute value is not
287             defined.
288              
289             =back
290              
291             The read-write attributes can be set with C constructor. Read-only
292             attributes and unknown attributes are ignored.
293              
294             The constant have to be defined in derived class if it brings additional
295             attributes.
296              
297             package Exception::My;
298             use base 'Exception::Base';
299              
300             # Define new class attributes
301             use constant ATTRS => {
302             %{Exception::Base->ATTRS}, # base's attributes have to be first
303             readonly => { is=>'ro' }, # new ro attribute
304             readwrite => { is=>'rw', default=>'blah' }, # new rw attribute
305             };
306              
307             package main;
308             use Exception::Base ':all';
309             eval {
310             Exception::My->throw( readwrite => 2 );
311             };
312             if ($@) {
313             my $e = Exception::Base->catch;
314             print $e->readwrite; # = 2
315             print $e->defaults->{readwrite}; # = "blah"
316             }
317              
318             =back
319              
320             =cut
321              
322             BEGIN {
323 1     1   2 my %ATTRS = ();
324              
325             =head1 ATTRIBUTES
326              
327             Class attributes are implemented as values of blessed hash. The attributes
328             are also available as accessors methods.
329              
330             =over
331              
332             =cut
333              
334             =item message (rw, default: 'Unknown exception')
335              
336             Contains the message of the exception. It is the part of the string
337             representing the exception object.
338              
339             eval { Exception::Base->throw( message=>"Message" ); };
340             print $@->message if $@;
341              
342             It can also be an array reference of strings and then the L
343             is used to get a message.
344              
345             Exception::Base->throw( message => ["%s failed", __PACKAGE__] );
346              
347             =cut
348              
349 1         6 $ATTRS{message} = { is => 'rw', default => 'Unknown exception' };
350              
351             =item value (rw, default: 0)
352              
353             Contains the value which represents numeric value of the exception object in
354             numeric context.
355              
356             eval { Exception::Base->throw( value=>2 ); };
357             print "Error 2" if $@ == 2;
358              
359             =cut
360              
361 1         2 $ATTRS{value} = { is => 'rw', default => 0 };
362              
363             =item verbosity (rw, default: 2)
364              
365             Contains the verbosity level of the exception object. It allows to change the
366             string representing the exception object. There are following levels of
367             verbosity:
368              
369             =over 2
370              
371             =item C<0>
372              
373             Empty string
374              
375             =item C<1>
376              
377             Message
378              
379             =item C<2>
380              
381             Message at %s line %d.
382              
383             The same as the standard output of die() function. It doesn't include
384             "at %s line %d." string if message ends with C<"\n"> character. This is
385             the default option.
386              
387             =item C<3>
388              
389             Class: Message at %s line %d
390             %c_ = %s::%s() called in package %s at %s line %d
391             ...propagated in package %s at %s line %d.
392             ...
393              
394             The output contains full trace of error stack without first C
395             lines and those packages which are listed in C and
396             C settings.
397              
398             =item S<4>
399              
400             The output contains full trace of error stack. In this case the
401             C, C and C settings are meaning
402             only for first line of exception's message.
403              
404             =back
405              
406             If the verbosity is undef, then the default verbosity for exception objects is
407             used.
408              
409             If the verbosity set with constructor (C or C) is lower than 3,
410             the full stack trace won't be collected.
411              
412             If the verbosity is lower than 2, the full system data (time, pid, tid, uid,
413             euid, gid, egid) won't be collected.
414              
415             This setting can be changed with import interface.
416              
417             use Exception::Base verbosity => 4;
418              
419             It can be also changed for Perl interpreter instance, i.e. for debugging
420             purposes.
421              
422             sh$ perl -MException::Base=verbosity,4 script.pl
423              
424             =cut
425              
426 1         3 $ATTRS{verbosity} = { is => 'rw', default => 2 };
427              
428             =item ignore_package (rw)
429              
430             Contains the name (scalar or regexp) or names (as references array) of
431             packages which are ignored in error stack trace. It is useful if some package
432             throws an exception but this module shouldn't be listed in stack trace.
433              
434             package My::Package;
435             use Exception::Base;
436             sub my_function {
437             do_something() or throw Exception::Base ignore_package=>__PACKAGE__;
438             throw Exception::Base ignore_package => [ "My", qr/^My::Modules::/ ];
439             }
440              
441             This setting can be changed with import interface.
442              
443             use Exception::Base ignore_package => __PACKAGE__;
444              
445             =cut
446              
447 1         3 $ATTRS{ignore_package} = { is => 'rw', default => [ ] };
448              
449             =item ignore_class (rw)
450              
451             Contains the name (scalar) or names (as references array) of packages which
452             are base classes for ignored packages in error stack trace. It means that
453             some packages will be ignored even the derived class was called.
454              
455             package My::Package;
456             use Exception::Base;
457             Exception::Base->throw( ignore_class => "My::Base" );
458              
459             This setting can be changed with import interface.
460              
461             use Exception::Base ignore_class => "My::Base";
462              
463             =cut
464              
465 1         2 $ATTRS{ignore_class} = { is => 'rw', default => [ ] };
466              
467             =item ignore_level (rw)
468              
469             Contains the number of level on stack trace to ignore. It is useful if some
470             package throws an exception but this module shouldn't be listed in stack
471             trace. It can be used with or without I attribute.
472              
473             # Convert warning into exception. The signal handler ignores itself.
474             use Exception::Base 'Exception::My::Warning';
475             $SIG{__WARN__} = sub {
476             Exception::My::Warning->throw( message => $_[0], ignore_level => 1 );
477             };
478              
479             =cut
480              
481 1         4 $ATTRS{ignore_level} = { is => 'rw', default => 0 };
482              
483             =item time (ro)
484              
485             Contains the timestamp of the thrown exception. Collected if the verbosity on
486             throwing exception was greater than 1.
487              
488             eval { Exception::Base->throw( message=>"Message" ); };
489             print scalar localtime $@->time;
490              
491             =cut
492              
493 1         2 $ATTRS{time} = { is => 'ro' };
494              
495             =item pid (ro)
496              
497             Contains the PID of the Perl process at time of thrown exception. Collected
498             if the verbosity on throwing exception was greater than 1.
499              
500             eval { Exception::Base->throw( message=>"Message" ); };
501             kill 10, $@->pid;
502              
503             =cut
504              
505 1         3 $ATTRS{pid} = { is => 'ro' };
506              
507             =item tid (ro)
508              
509             Contains the tid of the thread or undef if threads are not used. Collected
510             if the verbosity on throwing exception was greater than 1.
511              
512             =cut
513              
514 1         2 $ATTRS{tid} = { is => 'ro' };
515              
516             =item uid (ro)
517              
518             =cut
519              
520 1         2 $ATTRS{uid} = { is => 'ro' };
521              
522             =item euid (ro)
523              
524             =cut
525              
526 1         3 $ATTRS{euid} = { is => 'ro' };
527              
528              
529             =item gid (ro)
530              
531             =cut
532              
533 1         2 $ATTRS{gid} = { is => 'ro' };
534              
535             =item egid (ro)
536              
537             Contains the real and effective uid and gid of the Perl process at time of
538             thrown exception. Collected if the verbosity on throwing exception was
539             greater than 1.
540              
541             =cut
542              
543 1         2 $ATTRS{egid} = { is => 'ro' };
544              
545             =item caller_stack (ro)
546              
547             Contains the error stack as array of array with information about caller
548             functions. The first 8 elements of the array's row are the same as first 8
549             elements of the output of C function. Further elements are optional
550             and are the arguments of called function. Collected if the verbosity on
551             throwing exception was greater than 1. Contains only the first element of
552             caller stack if the verbosity was lower than 3.
553              
554             If the arguments of called function are references and
555             C::weaken> function is available then reference is weakened.
556              
557             eval { Exception::Base->throw( message=>"Message" ); };
558             ($package, $filename, $line, $subroutine, $hasargs, $wantarray,
559             $evaltext, $is_require, @args) = $@->caller_stack->[0];
560              
561             =cut
562              
563 1         2 $ATTRS{caller_stack} = { is => 'ro' };
564              
565             =item propagated_stack (ro)
566              
567             Contains the array of array which is used for generating "...propagated at"
568             message. The elements of the array's row are the same as first 3 elements of
569             the output of C function.
570              
571             =cut
572              
573 1         2 $ATTRS{propagated_stack} = { is => 'ro' };
574              
575             =item max_arg_len (rw, default: 64)
576              
577             Contains the maximal length of argument for functions in backtrace output.
578             Zero means no limit for length.
579              
580             sub a { Exception::Base->throw( max_arg_len=>5 ) }
581             a("123456789");
582              
583             =cut
584              
585 1         9 $ATTRS{max_arg_len} = { is => 'rw', default => 64 };
586              
587             =item max_arg_nums (rw, default: 8)
588              
589             Contains the maximal number of arguments for functions in backtrace output.
590             Zero means no limit for arguments.
591              
592             sub a { Exception::Base->throw( max_arg_nums=>1 ) }
593             a(1,2,3);
594              
595             =cut
596              
597 1         3 $ATTRS{max_arg_nums} = { is => 'rw', default => 8 };
598              
599             =item max_eval_len (rw, default: 0)
600              
601             Contains the maximal length of eval strings in backtrace output. Zero means
602             no limit for length.
603              
604             eval "Exception->throw( max_eval_len=>10 )";
605             print "$@";
606              
607             =cut
608              
609 1         8 $ATTRS{max_eval_len} = { is => 'rw', default => 0 };
610              
611             =item defaults
612              
613             Meta-attribute contains the list of default values.
614              
615             my $e = Exception::Base->new;
616             print defined $e->{verbosity}
617             ? $e->{verbosity}
618             : $e->{defaults}->{verbosity};
619              
620             =cut
621              
622 1         2 $ATTRS{defaults} = { };
623              
624             =item default_attribute (default: 'message')
625              
626             Meta-attribute contains the name of the default attribute. This attribute
627             will be set for one argument throw method. This attribute has meaning for
628             derived classes.
629              
630             use Exception::Base 'Exception::My' => {
631             has => 'myattr',
632             default_attribute => 'myattr',
633             };
634              
635             eval { Exception::My->throw("string") };
636             print $@->myattr; # "string"
637              
638             =cut
639              
640 1         22 $ATTRS{default_attribute} = { default => 'message' };
641              
642             =item numeric_attribute (default: 'value')
643              
644             Meta-attribute contains the name of the attribute which contains numeric value
645             of exception object. This attribute will be used for representing exception
646             in numeric context.
647              
648             use Exception::Base 'Exception::My' => {
649             has => 'myattr',
650             numeric_attribute => 'myattr',
651             };
652              
653             eval { Exception::My->throw(myattr=>123) };
654             print 0 + $@; # 123
655              
656             =cut
657              
658 1         3 $ATTRS{numeric_attribute} = { default => 'value' };
659              
660             =item eval_attribute (default: 'message')
661              
662             Meta-attribute contains the name of the attribute which is filled if error
663             stack is empty. This attribute will contain value of C<$@> variable. This
664             attribute has meaning for derived classes.
665              
666             use Exception::Base 'Exception::My' => {
667             has => 'myattr',
668             eval_attribute => 'myattr'
669             };
670              
671             eval { die "string" };
672             print $@->myattr; # "string"
673              
674             =cut
675              
676 1         2 $ATTRS{eval_attribute} = { default => 'message' };
677              
678             =item string_attributes (default: ['message'])
679              
680             Meta-attribute contains the array of names of attributes with defined value
681             which are joined to the string returned by C method. If none of
682             attributes are defined, the string is created from the first default value of
683             attributes listed in the opposite order.
684              
685             use Exception::Base 'Exception::My' => {
686             has => 'myattr',
687             myattr => 'default',
688             string_attributes => ['message', 'myattr'],
689             };
690              
691             eval { Exception::My->throw( message=>"string", myattr=>"foo" ) };
692             print $@->myattr; # "string: foo"
693              
694             eval { Exception::My->throw() };
695             print $@->myattr; # "default"
696              
697             =back
698              
699             =cut
700              
701 1         7 $ATTRS{string_attributes} = { default => [ 'message' ] };
702              
703 1     95   651 *ATTRS = sub () { \%ATTRS };
  95         1672  
704             };
705              
706              
707             # Cache for class' ATTRS
708             my %Class_Attributes;
709              
710              
711             # Cache for class' defaults
712             my %Class_Defaults;
713              
714              
715             # Cache for $obj->isa(__PACKAGE__)
716             my %Isa_Package;
717              
718              
719             =head1 IMPORTS
720              
721             =over
722              
723             =item C' => I;>
724              
725             Changes the default value for I. If the I name has no
726             special prefix, its default value is replaced with a new I.
727              
728             use Exception::Base verbosity => 4;
729              
730             If the I name starts with "C<+>" or "C<->" then the new I
731             is based on previous value:
732              
733             =over
734              
735             =item *
736              
737             If the original I was a reference to array, the new I can
738             be included or removed from original array. Use array reference if you
739             need to add or remove more than one element.
740              
741             use Exception::Base
742             "+ignore_packages" => [ __PACKAGE__, qr/^Moose::/ ],
743             "-ignore_class" => "My::Good::Class";
744              
745             =item *
746              
747             If the original I was a number, it will be incremented or
748             decremented by the new I.
749              
750             use Exception::Base "+ignore_level" => 1;
751              
752             =item *
753              
754             If the original I was a string, the new I will be
755             included.
756              
757             use Exception::Base "+message" => ": The incuded message";
758              
759             =back
760              
761             =item C', ...;>
762              
763             Loads additional exception class module. If the module is not available,
764             creates the exception class automatically at compile time. The newly created
765             class will be based on C class.
766              
767             use Exception::Base qw{ Exception::Custom Exception::SomethingWrong };
768             Exception::Custom->throw;
769              
770             =item C' => { isa => I, version => I, ... };>
771              
772             Loads additional exception class module. If the module's version is lower
773             than given parameter or the module can't be loaded, creates the exception
774             class automatically at compile time. The newly created class will be based on
775             given class and has the given $VERSION variable.
776              
777             =over
778              
779             =item isa
780              
781             The newly created class will be based on given class.
782              
783             use Exception::Base
784             'Exception::My',
785             'Exception::Nested' => { isa => 'Exception::My };
786              
787             =item version
788              
789             The class will be created only if the module's version is lower than given
790             parameter and will have the version given in the argument.
791              
792             use Exception::Base
793             'Exception::My' => { version => 1.23 };
794              
795             =item has
796              
797             The class will contain new rw attribute (if parameter is a string) or new rw
798             attributes (if parameter is a reference to array of strings) or new rw or ro
799             attributes (if parameter is a reference to hash of array of strings with rw
800             and ro as hash key).
801              
802             use Exception::Base
803             'Exception::Simple' => { has => 'field' },
804             'Exception::More' => { has => [ 'field1', 'field2' ] },
805             'Exception::Advanced' => { has => {
806             ro => [ 'field1', 'field2' ],
807             rw => [ 'field3' ]
808             } };
809              
810             =item message
811              
812             =item verbosity
813              
814             =item max_arg_len
815              
816             =item max_arg_nums
817              
818             =item max_eval_len
819              
820             =item I
821              
822             The class will have the default property for the given attribute.
823              
824             =back
825              
826             use Exception::Base
827             'Exception::WithDefault' => { message => 'Default message' },
828             'Exception::Reason' => {
829             has => [ 'reason' ],
830             string_attributes => [ 'message', 'reason' ] };
831              
832             =back
833              
834             =cut
835              
836             # Create additional exception packages
837             sub import {
838 54     54   4170 my $class = shift;
839              
840 54         146 while (defined $_[0]) {
841 52         84 my $name = shift @_;
842 52 100       265 if ($name eq ':all') {
    100          
843             # do nothing for backward compatibility
844             }
845             elsif ($name =~ /^([+-]?)([a-z0-9_]+)$/) {
846             # Lower case: change default
847 21         59 my ($modifier, $key) = ($1, $2);
848 21         29 my $value = shift;
849 21         73 $class->_modify_default($key, $value, $modifier);
850             }
851             else {
852             # Try to use external module
853 30         46 my $param = {};
854 30 100 66     161 $param = shift @_ if defined $_[0] and ref $_[0] eq 'HASH';
855              
856 30 100       71 my $version = defined $param->{version} ? $param->{version} : 0;
857              
858 30 100       117 if (caller ne $name) {
859 29 100       33 next if eval { $name->VERSION($version) };
  29         407  
860              
861             # Package is needed
862             {
863 27         40 local $SIG{__DIE__};
  27         98  
864 27         43 eval {
865 27         77 $class->_load_package($name, $version);
866             };
867             };
868 27 100       96 if ($@) {
869             # Die unless can't load module
870 26 100       98 if ($@ !~ /Can\'t locate/) {
871 3         16 Exception::Base->throw(
872             message => ["Can not load available %s class: %s", $name, $@],
873             verbosity => 1
874             );
875             };
876             }
877             else {
878             # Module is loaded: go to next
879 1         5 next;
880             };
881             };
882              
883 24 50       58 next if $name eq __PACKAGE__;
884              
885             # Package not found so it have to be created
886 24 100       64 if ($class ne __PACKAGE__) {
887 1         6 Exception::Base->throw(
888             message => ["Exceptions can only be created with %s class", __PACKAGE__],
889             verbosity => 1
890             );
891             };
892 23         65 $class->_make_exception($name, $version, $param);
893             }
894             }
895              
896 45         3955 return $class;
897             };
898              
899              
900             =head1 CONSTRUCTORS
901              
902             =over
903              
904             =item new([%I])
905              
906             Creates the exception object, which can be thrown later. The system data
907             attributes like C
908             filled.
909              
910             If the key of the argument is read-write attribute, this attribute will be
911             filled. Otherwise, the argument will be ignored.
912              
913             $e = Exception::Base->new(
914             message=>"Houston, we have a problem",
915             unknown_attr => "BIG"
916             );
917             print $e->{message};
918              
919             The constructor reads the list of class attributes from ATTRS constant
920             function and stores it in the internal cache for performance reason. The
921             defaults values for the class are also stored in internal cache.
922              
923             =item C-Ethrow([%I]])
924              
925             Creates the exception object and immediately throws it with C system
926             function.
927              
928             open my $fh, $file
929             or Exception::Base->throw( message=>"Can not open file: $file" );
930              
931             The C is also exported as a function.
932              
933             open my $fh, $file
934             or throw 'Exception::Base' => message=>"Can not open file: $file";
935              
936             =back
937              
938             The C can be also used as a method.
939              
940             =cut
941              
942             # Constructor
943             sub new {
944 72     72 1 14223 my ($self, %args) = @_;
945              
946 72   66     270 my $class = ref $self || $self;
947              
948 72         87 my $attributes;
949             my $defaults;
950              
951             # Use cached value if available
952 72 100       168 if (not defined $Class_Attributes{$class}) {
953 22         78 $attributes = $Class_Attributes{$class} = $class->ATTRS;
954             $defaults = $Class_Defaults{$class} = {
955 286         629 map { $_ => $attributes->{$_}->{default} }
956 22         126 grep { defined $attributes->{$_}->{default} }
  522         787  
957             (keys %$attributes)
958             };
959             }
960             else {
961 50         70 $attributes = $Class_Attributes{$class};
962 50         82 $defaults = $Class_Defaults{$class};
963             };
964              
965 72         175 my $e = {};
966              
967             # If the attribute is rw, initialize its value. Otherwise: ignore.
968 1     1   9 no warnings 'uninitialized';
  1         2  
  1         300  
969 72         188 foreach my $key (keys %args) {
970 50 100       146 if ($attributes->{$key}->{is} eq 'rw') {
971 46         116 $e->{$key} = $args{$key};
972             };
973             };
974              
975             # Defaults for this object
976 72         571 $e->{defaults} = { %$defaults };
977              
978 72         201 bless $e => $class;
979              
980             # Collect system data and eval error
981 72         220 $e->_collect_system_data;
982              
983 72         299 return $e;
984             };
985              
986              
987             =head1 METHODS
988              
989             =over
990              
991             =item C<$obj>-Ethrow([%I])
992              
993             Immediately throws exception object. It can be used for rethrowing existing
994             exception object. Additional arguments will override the attributes in
995             existing exception object.
996              
997             $e = Exception::Base->new;
998             # (...)
999             $e->throw( message=>"thrown exception with overridden message" );
1000              
1001             eval { Exception::Base->throw( message=>"Problem", value=>1 ) };
1002             $@->throw if $@->value;
1003              
1004             =item C<$obj>-Ethrow(I, [%I])
1005              
1006             If the number of I list for arguments is odd, the first argument is a
1007             message. This message can be overridden by message from I list.
1008              
1009             Exception::Base->throw( "Problem", message=>"More important" );
1010             eval { die "Bum!" };
1011             Exception::Base->throw( $@, message=>"New message" );
1012              
1013             =item I-Ethrow($I, [%I])
1014              
1015             Immediately rethrows an existing exception object as an other exception class.
1016              
1017             eval { open $f, "w", "/etc/passwd" or Exception::System->throw };
1018             # convert Exception::System into Exception::Base
1019             Exception::Base->throw($@);
1020              
1021             =cut
1022              
1023             # Create the exception and throw it or rethrow existing
1024             sub throw {
1025 36     36 1 849 my $self = shift;
1026              
1027 36   66     134 my $class = ref $self || $self;
1028              
1029 36         39 my $old_e;
1030              
1031 36 100       65 if (not ref $self) {
1032             # CLASS->throw
1033 34 100       59 if (not ref $_[0]) {
1034             # Throw new exception
1035 33 100       71 if (scalar @_ % 2 == 0) {
1036             # Throw normal error
1037 30         111 die $self->new(@_);
1038             }
1039             else {
1040             # First argument is a default attribute; it can be overridden with normal args
1041 3         5 my $argument = shift;
1042 3         11 my $e = $self->new(@_);
1043 3         7 my $default_attribute = $e->{defaults}->{default_attribute};
1044 3 100       11 $e->{$default_attribute} = $argument if not defined $e->{$default_attribute};
1045 3         13 die $e;
1046             };
1047             }
1048             else {
1049             # First argument is an old exception
1050 1         2 $old_e = shift;
1051             };
1052             }
1053             else {
1054             # $e->throw
1055 2         3 $old_e = $self;
1056             };
1057              
1058             # Rethrow old exception with replaced attributes
1059 1     1   5 no warnings 'uninitialized';
  1         1  
  1         672  
1060 3         7 my %args = @_;
1061 3         7 my $attrs = $old_e->ATTRS;
1062 3         8 foreach my $key (keys %args) {
1063 2 100       8 if ($attrs->{$key}->{is} eq 'rw') {
1064 1         3 $old_e->{$key} = $args{$key};
1065             };
1066             };
1067 3         9 $old_e->PROPAGATE;
1068 3 100       10 if (ref $old_e ne $class) {
1069             # Rebless old object for new class
1070 1         2 bless $old_e => $class;
1071             };
1072              
1073 3         13 die $old_e;
1074             };
1075              
1076              
1077             =item I-Ecatch([$I])
1078              
1079             The exception is recovered from I argument or C<$@> variable if
1080             I argument was empty. Then also C<$@> is replaced with empty string
1081             to avoid an endless loop.
1082              
1083             The method returns an exception object if exception is caught or undefined
1084             value otherwise.
1085              
1086             eval { Exception::Base->throw; };
1087             if ($@) {
1088             my $e = Exception::Base->catch;
1089             print $e->to_string;
1090             }
1091              
1092             If the value is not empty and does not contain the C object,
1093             new exception object is created with class I and its message is based
1094             on previous value with removed C<" at file line 123."> string and the last end
1095             of line (LF).
1096              
1097             eval { die "Died\n"; };
1098             my $e = Exception::Base->catch;
1099             print ref $e; # "Exception::Base"
1100              
1101             =cut
1102              
1103             # Recover $@ variable and return exception object
1104             sub catch {
1105 19     19 1 794 my ($self) = @_;
1106              
1107 19   66     78 my $class = ref $self || $self;
1108              
1109 19         23 my $e;
1110             my $new_e;
1111              
1112              
1113 19 100       42 if (@_ > 1) {
1114             # Recover exception from argument
1115 1         2 $e = $_[1];
1116             }
1117             else {
1118             # Recover exception from $@ and clear it
1119 18         22 $e = $@;
1120 18         31 $@ = '';
1121             };
1122              
1123 19 100 66     64 if (ref $e and do { local $@; local $SIG{__DIE__}; eval { $e->isa(__PACKAGE__) } }) {
  4 100       5  
  4         14  
  4         7  
  4         25  
1124             # Caught exception
1125 3         6 $new_e = $e;
1126             }
1127             elsif ($e eq '') {
1128             # No error in $@
1129 2         3 $new_e = undef;
1130             }
1131             else {
1132             # New exception based on error from $@. Clean up the message.
1133 14         58 while ($e =~ s/\t\.\.\.propagated at (?!.*\bat\b.*).* line \d+( thread \d+)?\.\n$//s) { };
1134 14         106 $e =~ s/( at (?!.*\bat\b.*).* line \d+( thread \d+)?\.)?\n$//s;
1135 14         52 $new_e = $class->new;
1136 14         26 my $eval_attribute = $new_e->{defaults}->{eval_attribute};
1137 14         30 $new_e->{$eval_attribute} = $e;
1138             };
1139              
1140 19         49 return $new_e;
1141             };
1142              
1143              
1144             =item matches(I)
1145              
1146             Checks if the exception object matches the given argument.
1147              
1148             The C method overloads C<~~> smart matching operator. Warning: The
1149             second argument for smart matching operator needs to be scalar.
1150              
1151             If the argument is a reference to array, it is checked if the object is a
1152             given class.
1153              
1154             use Exception::Base
1155             'Exception::Simple',
1156             'Exception::Complex' => { isa => 'Exception::Simple };
1157             eval { Exception::Complex->throw() };
1158             print $@->matches( ['Exception::Base'] ); # matches
1159             print $@->matches( ['Exception::Simple', 'Exception::X'] ); # matches
1160             print $@->matches( ['NullObject'] ); # doesn't
1161              
1162             If the argument is a reference to hash, attributes of the exception
1163             object is matched.
1164              
1165             eval { Exception::Base->throw( message=>"Message", value=>123 ) };
1166             print $@->matches( { message=>"Message" } ); # matches
1167             print $@->matches( { value=>123 } ); # matches
1168             print $@->matches( { message=>"Message", value=>45 } ); # doesn't
1169              
1170             If the argument is a single string, regexp or code reference or is undefined,
1171             the default attribute of the exception object is matched (usually it is a
1172             "message" attribute).
1173              
1174             eval { Exception::Base->throw( message=>"Message" ) };
1175             print $@->matches( "Message" ); # matches
1176             print $@->matches( qr/Message/ ); # matches
1177             print $@->matches( qr/[0-9]/ ); # doesn't
1178             print $@->matches( sub{/Message/} ); # matches
1179             print $@->matches( sub{0} ); # doesn't
1180             print $@->matches( undef ); # doesn't
1181              
1182             If argument is a numeric value, the argument matches if C attribute
1183             matches.
1184              
1185             eval { Exception::Base->throw( value=>123, message=>456 ) } );
1186             print $@->matches( 123 ); # matches
1187             print $@->matches( 456 ); # doesn't
1188              
1189             If an attribute contains array reference, the array will be C-ed
1190             before matching.
1191              
1192             eval { Exception::Base->throw( message=>["%s", "Message"] ) };
1193             print $@->matches( "Message" ); # matches
1194             print $@->matches( qr/Message/ ); # matches
1195             print $@->matches( qr/[0-9]/ ); # doesn't
1196              
1197             The C method matches for special keywords:
1198              
1199             =over
1200              
1201             =item -isa
1202              
1203             Matches if the object is a given class.
1204              
1205             eval { Exception::Base->new( message=>"Message" ) };
1206             print $@->matches( { -isa=>"Exception::Base" } ); # matches
1207             print $@->matches( { -isa=>["X::Y", "Exception::Base"] } ); # matches
1208              
1209             =item -has
1210              
1211             Matches if the object has a given attribute.
1212              
1213             eval { Exception::Base->new( message=>"Message" ) };
1214             print $@->matches( { -has=>"Message" } ); # matches
1215              
1216             =item -default
1217              
1218             Matches against the default attribute, usually the C attribute.
1219              
1220             eval { Exception::Base->new( message=>"Message" ) };
1221             print $@->matches( { -default=>"Message" } ); # matches
1222              
1223             =back
1224              
1225             =cut
1226              
1227             # Smart matching.
1228             sub matches {
1229 159     159 1 461 my ($self, $that) = @_;
1230              
1231 159         187 my @args;
1232              
1233 159         314 my $default_attribute = $self->{defaults}->{default_attribute};
1234 159         238 my $numeric_attribute = $self->{defaults}->{numeric_attribute};
1235              
1236 159 100 100     800 if (ref $that eq 'ARRAY') {
    100 100        
    100          
    100          
    100          
1237 7         16 @args = ( '-isa' => $that );
1238             }
1239             elsif (ref $that eq 'HASH') {
1240 100         285 @args = %$that;
1241             }
1242             elsif (ref $that eq 'Regexp' or ref $that eq 'CODE' or not defined $that) {
1243 24         51 @args = ( $that );
1244             }
1245             elsif (ref $that) {
1246 3         13 return '';
1247             }
1248             elsif ($that =~ _RE_NUM_INT) {
1249 13         30 @args = ( $numeric_attribute => $that );
1250             }
1251             else {
1252 12         24 @args = ( $that );
1253             };
1254              
1255 156 50       363 return '' unless @args;
1256              
1257             # Odd number of arguments - first is default attribute
1258 156 100       376 if (scalar @args % 2 == 1) {
1259 36         52 my $val = shift @args;
1260 36 50 66     203 if (ref $val eq 'ARRAY') {
    100          
    50          
    100          
1261 0         0 my $arrret = 0;
1262 0         0 foreach my $arrval (@{ $val }) {
  0         0  
1263 0 0 0     0 if (not defined $arrval) {
    0          
    0          
1264 0 0       0 $arrret = 1 if not $self->_string_attributes;
1265             }
1266             elsif (not ref $arrval and $arrval =~ _RE_NUM_INT) {
1267 1     1   6 no warnings 'numeric', 'uninitialized';
  1         1  
  1         178  
1268 0 0       0 $arrret = 1 if $self->{$numeric_attribute} == $arrval;
1269             }
1270             elsif (not $self->_string_attributes) {
1271 0         0 next;
1272             }
1273             else {
1274 0         0 local $_ = join ': ', $self->_string_attributes;
1275 0 0       0 if (ref $arrval eq 'CODE') {
    0          
1276 0 0       0 $arrret = 1 if $arrval->();
1277             }
1278             elsif (ref $arrval eq 'Regexp') {
1279 0 0       0 $arrret = 1 if /$arrval/;
1280             }
1281             else {
1282 0 0       0 $arrret = 1 if $_ eq $arrval;
1283             };
1284             };
1285 0 0       0 last if $arrret;
1286             };
1287             # Fail unless at least one condition is true
1288 0 0       0 return '' if not $arrret;
1289             }
1290             elsif (not defined $val) {
1291 8 100       23 return '' if $self->_string_attributes;
1292             }
1293             elsif (not ref $val and $val =~ _RE_NUM_INT) {
1294 1     1   6 no warnings 'numeric', 'uninitialized';
  1         17  
  1         562  
1295 0 0       0 return '' if $self->{$numeric_attribute} != $val;
1296             }
1297             elsif (not $self->_string_attributes) {
1298 7         35 return '';
1299             }
1300             else {
1301 21         49 local $_ = join ': ', $self->_string_attributes;
1302 21 100       73 if (ref $val eq 'CODE') {
    100          
1303 6 100       18 return '' if not $val->();
1304             }
1305             elsif (ref $val eq 'Regexp') {
1306 6 100       42 return '' if not /$val/;
1307             }
1308             else {
1309 9 100       47 return '' if $_ ne $val;
1310             };
1311             };
1312 17 50       142 return 1 unless @args;
1313             };
1314              
1315 120         253 my %args = @args;
1316 120         360 while (my($key,$val) = each %args) {
1317 126 100       265 if ($key eq '-default') {
1318 6         11 $key = $default_attribute;
1319             };
1320              
1321 126 100 100     675 if ($key eq '-isa') {
    100          
    100          
    100          
    100          
    100          
1322 11 100       23 if (ref $val eq 'ARRAY') {
1323 9         18 my $arrret = 0;
1324 9         9 foreach my $arrval (@{ $val }) {
  9         20  
1325 21 50       39 next if not defined $arrval;
1326 21 100       81 $arrret = 1 if $self->isa($arrval);
1327 21 100       43 last if $arrret;
1328             };
1329 9 100       47 return '' if not $arrret;
1330             }
1331             else {
1332 2 100       16 return '' if not $self->isa($val);
1333             };
1334             }
1335             elsif ($key eq '-has') {
1336 4 100       18 if (ref $val eq 'ARRAY') {
1337 2         17 my $arrret = 0;
1338 2         3 foreach my $arrval (@{ $val }) {
  2         5  
1339 5 50       12 next if not defined $arrval;
1340 5 100       11 $arrret = 1 if exists $self->ATTRS->{$arrval};
1341 5 100       14 last if $arrret;
1342             };
1343 2 100       20 return '' if not $arrret;
1344             }
1345             else {
1346 2 100       7 return '' if not $self->ATTRS->{$val};
1347             };
1348             }
1349             elsif (ref $val eq 'ARRAY') {
1350 38         46 my $arrret = 0;
1351 38         44 foreach my $arrval (@{ $val }) {
  38         80  
1352 77 100       182 if (not defined $arrval) {
    100          
1353 17 100       45 $arrret = 1 if not defined $self->{$key};
1354             }
1355             elsif (not defined $self->{$key}) {
1356 24         49 next;
1357             }
1358             else {
1359             local $_ = ref $self->{$key} eq 'ARRAY'
1360             ? sprintf(
1361 9         20 @{$self->{$key}}[0],
1362 9         25 @{$self->{$key}}[1..$#{$self->{$key}}]
  9         20  
1363             )
1364 36 100       91 : $self->{$key};
1365 36 100       94 if (ref $arrval eq 'CODE') {
    100          
1366 8 100       22 $arrret = 1 if $arrval->();
1367             }
1368             elsif (ref $arrval eq 'Regexp') {
1369 12 100       61 $arrret = 1 if /$arrval/;
1370             }
1371             else {
1372 16 100       49 $arrret = 1 if $_ eq $arrval;
1373             };
1374             };
1375 53 100       159 last if $arrret;
1376             };
1377 38 100       217 return '' if not $arrret;
1378             }
1379             elsif (not defined $val) {
1380 12 100 100     93 return '' if exists $self->{$key} && defined $self->{$key};
1381             }
1382             elsif (not ref $val and $val =~ _RE_NUM_INT) {
1383 1     1   5 no warnings 'numeric', 'uninitialized';
  1         1  
  1         561  
1384 17 100       173 return '' if $self->{$key} != $val;
1385             }
1386             elsif (not defined $self->{$key}) {
1387 10         52 return '';
1388             }
1389             else {
1390             local $_ = ref $self->{$key} eq 'ARRAY'
1391             ? sprintf(
1392 10         24 @{$self->{$key}}[0],
1393 10         33 @{$self->{$key}}[1..$#{$self->{$key}}]
  10         16  
1394             )
1395 34 100       96 : $self->{$key};
1396              
1397 34 100       95 if (ref $val eq 'CODE') {
    100          
1398 12 100       31 return '' if not $val->();
1399             }
1400             elsif (ref $val eq 'Regexp') {
1401 12 100       103 return '' if not /$val/;
1402             }
1403             else {
1404 10 100       60 return '' if $_ ne $val;
1405             };
1406             };
1407             };
1408              
1409 62         388 return 1;
1410             }
1411              
1412              
1413             =item to_string
1414              
1415             Returns the string representation of exception object. It is called
1416             automatically if the exception object is used in string scalar context. The
1417             method can be used explicitly.
1418              
1419             eval { Exception::Base->throw; };
1420             $@->{verbosity} = 1;
1421             print "$@";
1422             $@->verbosity = 4;
1423             print $@->to_string;
1424              
1425             =cut
1426              
1427             # Convert an exception to string
1428             sub to_string {
1429 58     58 1 566 my ($self) = @_;
1430              
1431             my $verbosity = defined $self->{verbosity}
1432             ? $self->{verbosity}
1433 58 100       153 : $self->{defaults}->{verbosity};
1434              
1435 58         135 my $message = join ': ', $self->_string_attributes;
1436              
1437 58 100       153 if ($message eq '') {
1438 4         4 foreach (reverse @{ $self->{defaults}->{string_attributes} }) {
  4         15  
1439 4         7 $message = $self->{defaults}->{$_};
1440 4 50       12 last if defined $message;
1441             };
1442             };
1443              
1444 58 100       205 if ($verbosity == 1) {
    100          
    100          
1445 18 100       74 return $message if $message =~ /\n$/;
1446              
1447 14         77 return $message . "\n";
1448             }
1449             elsif ($verbosity == 2) {
1450 20 100       56 return $message if $message =~ /\n$/;
1451              
1452 19         44 my @stacktrace = $self->get_caller_stacktrace;
1453 19         112 return $message . $stacktrace[0] . ".\n";
1454             }
1455             elsif ($verbosity >= 3) {
1456 16         51 return ref($self) . ': ' . $message . $self->get_caller_stacktrace;
1457             };
1458              
1459 4         19 return '';
1460             };
1461              
1462              
1463             =item to_number
1464              
1465             Returns the numeric representation of exception object. It is called
1466             automatically if the exception object is used in numeric scalar context. The
1467             method can be used explicitly.
1468              
1469             eval { Exception::Base->throw( value => 42 ); };
1470             print 0+$@; # 42
1471             print $@->to_number; # 42
1472              
1473             =cut
1474              
1475             # Convert an exception to number
1476             sub to_number {
1477 9     9 1 44 my ($self) = @_;
1478              
1479 9         16 my $numeric_attribute = $self->{defaults}->{numeric_attribute};
1480              
1481 1     1   5 no warnings 'numeric';
  1         7  
  1         2198  
1482 9 100       34 return 0+ $self->{$numeric_attribute} if defined $self->{$numeric_attribute};
1483 6 100       28 return 0+ $self->{defaults}->{$numeric_attribute} if defined $self->{defaults}->{$numeric_attribute};
1484 2         7 return 0;
1485             };
1486              
1487              
1488             =item to_bool
1489              
1490             Returns the boolean representation of exception object. It is called
1491             automatically if the exception object is used in boolean context. The method
1492             can be used explicitly.
1493              
1494             eval { Exception::Base->throw; };
1495             print "ok" if $@; # ok
1496             print "ok" if $@->to_bool; # ok
1497              
1498             =cut
1499              
1500             # Convert an exception to bool (always true)
1501             sub to_bool {
1502 1     1 1 38 return !! 1;
1503             };
1504              
1505              
1506             =item get_caller_stacktrace
1507              
1508             Returns an array of strings or string with caller stack trace. It is
1509             implicitly used by C method.
1510              
1511             =cut
1512              
1513             # Stringify caller backtrace. Stolen from Carp
1514             sub get_caller_stacktrace {
1515 35     35 1 50 my ($self) = @_;
1516              
1517 35         45 my @stacktrace;
1518              
1519 35         43 my $tid_msg = '';
1520 35 50       72 $tid_msg = ' thread ' . $self->{tid} if $self->{tid};
1521              
1522             my $verbosity = defined $self->{verbosity}
1523             ? $self->{verbosity}
1524 35 100       84 : $self->{defaults}->{verbosity};
1525              
1526             my $ignore_level = defined $self->{ignore_level}
1527             ? $self->{ignore_level}
1528             : defined $self->{defaults}->{ignore_level}
1529             ? $self->{defaults}->{ignore_level}
1530 35 50       85 : 0;
    100          
1531              
1532             # Skip some packages for first line
1533 35         37 my $level = 0;
1534 35         86 while (my %c = $self->_caller_info($level++)) {
1535 79 100       209 next if $self->_skip_ignored_package($c{package});
1536             # Skip ignored levels
1537 36 100       71 if ($ignore_level > 0) {
1538 5         6 --$ignore_level;
1539 5         25 next;
1540             };
1541             push @stacktrace, sprintf " at %s line %s%s",
1542             defined $c{file} && $c{file} ne '' ? $c{file} : 'unknown',
1543 31 50 33     271 $c{line} || 0,
      50        
1544             $tid_msg;
1545 31         86 last;
1546             };
1547             # First line have to be filled even if everything was skipped
1548 35 100       121 if (not @stacktrace) {
1549 4         9 my %c = $self->_caller_info(0);
1550             push @stacktrace, sprintf " at %s line %s%s",
1551             defined $c{file} && $c{file} ne '' ? $c{file} : 'unknown',
1552 4 100 66     46 $c{line} || 0,
      100        
1553             $tid_msg;
1554             };
1555 35 100       79 if ($verbosity >= 3) {
1556             # Reset the stack trace level only if needed
1557 16 100       33 if ($verbosity >= 4) {
1558 4         42 $level = 0;
1559             };
1560             # Dump the caller stack
1561 16         40 while (my %c = $self->_caller_info($level++)) {
1562 24 50 66     64 next if $verbosity == 3 and $self->_skip_ignored_package($c{package});
1563 24         186 push @stacktrace, "\t$c{wantarray}$c{sub_name} called in package $c{package} at $c{file} line $c{line}";
1564             };
1565             # Dump the propagated stack
1566 16         26 foreach (@{ $self->{propagated_stack} }) {
  16         49  
1567 24         54 my ($package, $file, $line) = @$_;
1568             # Skip ignored package
1569 24 100 100     81 next if $verbosity <= 3 and $self->_skip_ignored_package($package);
1570 19 50 33     177 push @stacktrace, sprintf "\t...propagated in package %s at %s line %d.",
      50        
1571             $package,
1572             defined $file && $file ne '' ? $file : 'unknown',
1573             $line || 0;
1574             };
1575             };
1576              
1577 35 100       241 return wantarray ? @stacktrace : join("\n", @stacktrace) . "\n";
1578             };
1579              
1580              
1581             =item PROPAGATE
1582              
1583             Checks the caller stack and fills the C attribute. It is
1584             usually used if C system function was called without any arguments.
1585              
1586             =cut
1587              
1588             # Propagate exception if it is rethrown
1589             sub PROPAGATE {
1590 3     3 1 5 my ($self) = @_;
1591              
1592             # Fill propagate stack
1593 3         4 my $level = 1;
1594 3         24 while (my @c = caller($level++)) {
1595             # Skip own package
1596             next if ! defined $Isa_Package{$c[0]}
1597 0         0 ? $Isa_Package{$c[0]} = do { local $@; local $SIG{__DIE__}; eval { $c[0]->isa(__PACKAGE__) } }
  0         0  
  0         0  
  0         0  
1598 3 50       12 : $Isa_Package{$c[0]};
    50          
1599             # Collect the caller stack
1600 3         4 push @{ $self->{propagated_stack} }, [ @c[0..2] ];
  3         10  
1601 3         7 last;
1602             };
1603              
1604 3         6 return $self;
1605             };
1606              
1607              
1608             # Return a list of values of default string attributes
1609             sub _string_attributes {
1610 115     115   161 my ($self) = @_;
1611              
1612 111 100       511 return map { ref $_ eq 'ARRAY'
1613             ? sprintf(@$_[0], @$_[1..$#$_])
1614             : $_ }
1615 136 100 100     717 grep { defined $_ and (ref $_ or $_ ne '') }
1616 136         334 map { $self->{$_} }
1617 115         138 @{ $self->{defaults}->{string_attributes} };
  115         276  
1618             };
1619              
1620              
1621             =item _collect_system_data
1622              
1623             Collects system data and fills the attributes of exception object. This
1624             method is called automatically if exception if thrown or created by
1625             C constructor. It can be overridden by derived class.
1626              
1627             package Exception::Special;
1628             use base 'Exception::Base';
1629             use constant ATTRS => {
1630             %{Exception::Base->ATTRS},
1631             'special' => { is => 'ro' },
1632             };
1633             sub _collect_system_data {
1634             my $self = shift;
1635             $self->SUPER::_collect_system_data(@_);
1636             $self->{special} = get_special_value();
1637             return $self;
1638             }
1639             BEGIN {
1640             __PACKAGE__->_make_accessors;
1641             }
1642             1;
1643              
1644             Method returns the reference to the self object.
1645              
1646             =cut
1647              
1648             # Collect system data and fill the attributes and caller stack.
1649             sub _collect_system_data {
1650 73     73   125 my ($self) = @_;
1651              
1652             # Collect system data only if verbosity is meaning
1653 73 100       1331 my $verbosity = defined $self->{verbosity} ? $self->{verbosity} : $self->{defaults}->{verbosity};
1654 73 100       182 if ($verbosity >= 2) {
1655 62         116 $self->{time} = CORE::time();
1656 62 50       144 $self->{tid} = threads->tid if defined &threads::tid;
1657 62         101 @{$self}{qw < pid uid euid gid egid >} =
  62         467  
1658             ( $$, $<, $>, $(, $) );
1659              
1660             # Collect stack info
1661 62         99 my @caller_stack;
1662 62         79 my $level = 1;
1663              
1664 62         96 while (my @c = do { package DB; caller($level++) }) {
  102         941  
1665             # Skip own package
1666 102 100       404 next if ! defined $Isa_Package{$c[0]} ? $Isa_Package{$c[0]} = do { local $@; local $SIG{__DIE__}; eval { $c[0]->isa(__PACKAGE__) } } : $Isa_Package{$c[0]};
  3 100       4  
  3         12  
  3         6  
  3         34  
1667             # Collect the caller stack
1668 62         134 my @args = @DB::args;
1669 62         66 if (_HAVE_SCALAR_UTIL_WEAKEN) {
1670 62         114 foreach (@args) {
1671 131 100       340 Scalar::Util::weaken($_) if ref $_;
1672             };
1673             };
1674 62         240 my @stacktrace_element = ( @c[0 .. 7], @args );
1675 62         110 push @caller_stack, \@stacktrace_element;
1676             # Collect only one entry if verbosity is lower than 3 and skip ignored packages
1677 62 50 33     294 last if $verbosity == 2 and not $self->_skip_ignored_package($stacktrace_element[0]);
1678             };
1679 62         253 $self->{caller_stack} = \@caller_stack;
1680             };
1681              
1682 73         123 return $self;
1683             };
1684              
1685              
1686             # Check if package should be ignored
1687             sub _skip_ignored_package {
1688 185     185   274 my ($self, $package) = @_;
1689              
1690             my $ignore_package = defined $self->{ignore_package}
1691             ? $self->{ignore_package}
1692 185 100       468 : $self->{defaults}->{ignore_package};
1693              
1694             my $ignore_class = defined $self->{ignore_class}
1695             ? $self->{ignore_class}
1696 185 100       482 : $self->{defaults}->{ignore_class};
1697              
1698 185 50       372 if (defined $ignore_package) {
1699 185 100       418 if (ref $ignore_package eq 'ARRAY') {
1700 140 100       160 if (@{ $ignore_package }) {
  140         391  
1701 20 100 66     23 do { return 1 if defined $_ and (ref $_ eq 'Regexp' and $package =~ $_ or ref $_ ne 'Regexp' and $package eq $_) } foreach @{ $ignore_package };
  20   33     47  
  40         443  
1702             };
1703             }
1704             else {
1705 45 100       306 return 1 if ref $ignore_package eq 'Regexp' ? $package =~ $ignore_package : $package eq $ignore_package;
    100          
1706             };
1707             }
1708 147 50       317 if (defined $ignore_class) {
1709 147 100       292 if (ref $ignore_class eq 'ARRAY') {
1710 138 100       154 if (@{ $ignore_class }) {
  138         334  
1711 14 100       17 return 1 if grep { do { local $@; local $SIG{__DIE__}; eval { $package->isa($_) } } } @{ $ignore_class };
  42         77  
  42         41  
  42         107  
  42         60  
  42         292  
  14         22  
1712             };
1713             }
1714             else {
1715 9 100       12 return 1 if do { local $@; local $SIG{__DIE__}; eval { $package->isa($ignore_class) } };
  9         12  
  9         25  
  9         13  
  9         126  
1716             };
1717             };
1718              
1719 133         640 return '';
1720             };
1721              
1722              
1723             # Return info about caller. Stolen from Carp
1724             sub _caller_info {
1725 160     160   258 my ($self, $i) = @_;
1726 160         187 my %call_info;
1727 160         248 my @call_info = ();
1728              
1729 138         421 @call_info = @{ $self->{caller_stack}->[$i] }
1730 160 100 66     841 if defined $self->{caller_stack} and defined $self->{caller_stack}->[$i];
1731              
1732             @call_info{
1733 160         727 qw{ package file line subroutine has_args wantarray evaltext is_require }
1734             } = @call_info[0..7];
1735              
1736 160 100       418 unless (defined $call_info{package}) {
1737 22         101 return ();
1738             };
1739              
1740 138         318 my $sub_name = $self->_get_subname(\%call_info);
1741 138 100       318 if ($call_info{has_args}) {
1742 74         150 my @args = map {$self->_format_arg($_)} @call_info[8..$#call_info];
  307         746  
1743 74 100       308 my $max_arg_nums = defined $self->{max_arg_nums} ? $self->{max_arg_nums} : $self->{defaults}->{max_arg_nums};
1744 74 100 100     333 if ($max_arg_nums > 0 and $#args+1 > $max_arg_nums) {
1745 25         77 $#args = $max_arg_nums - 2;
1746 25         47 push @args, '...';
1747             };
1748             # Push the args onto the subroutine
1749 74         303 $sub_name .= '(' . join (', ', @args) . ')';
1750             }
1751 138 100       311 $call_info{file} = 'unknown' unless $call_info{file};
1752 138 100       271 $call_info{line} = 0 unless $call_info{line};
1753 138         262 $call_info{sub_name} = $sub_name;
1754 138 100       310 $call_info{wantarray} = $call_info{wantarray} ? '@_ = ' : '$_ = ';
1755              
1756 138 100       1291 return wantarray() ? %call_info : \%call_info;
1757             };
1758              
1759              
1760             # Figures out the name of the sub/require/eval. Stolen from Carp
1761             sub _get_subname {
1762 146     146   223 my ($self, $info) = @_;
1763 146 100       314 if (defined($info->{evaltext})) {
1764 26         40 my $eval = $info->{evaltext};
1765 26 100       55 if ($info->{is_require}) {
1766 2         8 return "require $eval";
1767             }
1768             else {
1769 24         56 $eval =~ s/([\\\'])/\\$1/g;
1770             return
1771             "eval '" .
1772 24 100       78 $self->_str_len_trim($eval, defined $self->{max_eval_len} ? $self->{max_eval_len} : $self->{defaults}->{max_eval_len}) .
1773             "'";
1774             };
1775             };
1776              
1777 120 100       387 return ($info->{subroutine} eq '(eval)') ? 'eval {...}' : $info->{subroutine};
1778             };
1779              
1780              
1781             # Transform an argument to a function into a string. Stolen from Carp
1782             sub _format_arg {
1783 327     327   585 my ($self, $arg) = @_;
1784              
1785 327 100       664 return 'undef' if not defined $arg;
1786              
1787 325 100 100     382 if (do { local $@; local $SIG{__DIE__}; eval { $arg->isa(__PACKAGE__) } } or ref $arg) {
  325         389  
  325         925  
  325         494  
  325         2954  
1788 22         65 return q{"} . overload::StrVal($arg) . q{"};
1789             };
1790              
1791 303         452 $arg =~ s/\\/\\\\/g;
1792 303         366 $arg =~ s/"/\\"/g;
1793 303         346 $arg =~ s/`/\\`/g;
1794 303 100       982 $arg = $self->_str_len_trim($arg, defined $self->{max_arg_len} ? $self->{max_arg_len} : $self->{defaults}->{max_arg_len});
1795              
1796 303 100       1050 $arg = "\"$arg\"" unless $arg =~ /^-?[\d.]+\z/;
1797              
1798 1     1   12 no warnings 'once', 'utf8'; # can't disable critic for utf8...
  1         2  
  1         661  
1799 303 50 33     874 if (not defined *utf8::is_utf{CODE} or utf8::is_utf8($arg)) {
1800 303 100       745 $arg = join('', map { $_ > 255
  761 100       3404  
1801             ? sprintf("\\x{%04x}", $_)
1802             : chr($_) =~ /[[:cntrl:]]|[[:^ascii:]]/
1803             ? sprintf("\\x{%02x}", $_)
1804             : chr($_)
1805             } unpack("U*", $arg));
1806             }
1807             else {
1808 0         0 $arg =~ s/([[:cntrl:]]|[[:^ascii:]])/sprintf("\\x{%02x}",ord($1))/eg;
  0         0  
1809             };
1810              
1811 303         901 return $arg;
1812             };
1813              
1814              
1815             # If a string is too long, trims it with ... . Stolen from Carp
1816             sub _str_len_trim {
1817 369     369   896 my (undef, $str, $max) = @_;
1818 369 100       775 $max = 0 unless defined $max;
1819 369 100 100     1436 if ($max > 2 and $max < length($str)) {
1820 66         115 substr($str, $max - 3) = '...';
1821             };
1822              
1823 369         881 return $str;
1824             };
1825              
1826              
1827             # Modify default values for ATTRS
1828             sub _modify_default {
1829 21     21   38 my ($self, $key, $value, $modifier) = @_;
1830              
1831 21   33     84 my $class = ref $self || $self;
1832              
1833             # Modify entry in ATTRS constant. Its elements are not constant.
1834 21         48 my $attributes = $class->ATTRS;
1835              
1836 21 100       85 if (not exists $attributes->{$key}->{default}) {
1837 1         8 Exception::Base->throw(
1838             message => ["%s class does not implement default value for `%s' attribute", $class, $key],
1839             verbosity => 1
1840             );
1841             };
1842              
1843             # Make a new anonymous hash reference for attribute
1844 20         22 $attributes->{$key} = { %{ $attributes->{$key} } };
  20         80  
1845              
1846             # Modify default value of attribute
1847 20 100       54 if ($modifier eq '+') {
    100          
1848 7         15 my $old = $attributes->{$key}->{default};
1849 7 100 66     33 if (ref $old eq 'ARRAY' or ref $value eq 'Regexp') {
    100          
1850 5 50       9 my @new = ref $old eq 'ARRAY' ? @{ $old } : $old;
  5         14  
1851 5 100       13 foreach my $v (ref $value eq 'ARRAY' ? @{ $value } : $value) {
  3         7  
1852 9 50       18 next if grep { $v eq $_ } ref $old eq 'ARRAY' ? @{ $old } : $old;
  28 100       46  
  9         16  
1853 5         10 push @new, $v;
1854             };
1855 5         21 $attributes->{$key}->{default} = [ @new ];
1856             }
1857             elsif ($old =~ /^\d+$/) {
1858 1         4 $attributes->{$key}->{default} += $value;
1859             }
1860             else {
1861 1         10 $attributes->{$key}->{default} .= $value;
1862             };
1863             }
1864             elsif ($modifier eq '-') {
1865 6         12 my $old = $attributes->{$key}->{default};
1866 6 100 66     33 if (ref $old eq 'ARRAY' or ref $value eq 'Regexp') {
    100          
1867 4 50       8 my @new = ref $old eq 'ARRAY' ? @{ $old } : $old;
  4         17  
1868 4 100       10 foreach my $v (ref $value eq 'ARRAY' ? @{ $value } : $value) {
  3         7  
1869 7         13 @new = grep { $v ne $_ } @new;
  20         34  
1870             };
1871 4         13 $attributes->{$key}->{default} = [ @new ];
1872             }
1873             elsif ($old =~ /^\d+$/) {
1874 1         3 $attributes->{$key}->{default} -= $value;
1875             }
1876             else {
1877 1         5 $attributes->{$key}->{default} = $value;
1878             };
1879             }
1880             else {
1881 7         15 $attributes->{$key}->{default} = $value;
1882             };
1883              
1884             # Redeclare constant
1885             {
1886 1     1   6 no warnings 'redefine';
  1         2  
  1         188  
  20         26  
1887 20         69 *{_qualify_to_ref("${class}::ATTRS")} = sub () {
1888 32     32   614 +{ %$attributes };
1889 20         62 };
1890             };
1891              
1892             # Reset cache
1893 20         391 %Class_Attributes = %Class_Defaults = ();
1894              
1895 20         79 return $self;
1896             };
1897              
1898              
1899             =item _make_accessors
1900              
1901             Creates accessors for each attribute. This static method should be called in
1902             each derived class which defines new attributes.
1903              
1904             package Exception::My;
1905             # (...)
1906             BEGIN {
1907             __PACKAGE__->_make_accessors;
1908             }
1909              
1910             =cut
1911              
1912             # Create accessors for this class
1913             sub _make_accessors {
1914 20     20   33 my ($self) = @_;
1915              
1916 20   33     95 my $class = ref $self || $self;
1917              
1918 1     1   4 no warnings 'uninitialized';
  1         2  
  1         1332  
1919 20         57 my $attributes = $class->ATTRS;
1920 20         56 foreach my $key (keys %{ $attributes }) {
  20         103  
1921 470 50       1467 next if ref $attributes->{$key} ne 'HASH';
1922 470 100       3504 if (not $class->can($key)) {
1923 128 100       347 next if not defined $attributes->{$key}->{is};
1924 28 100       64 if ($attributes->{$key}->{is} eq 'rw') {
1925 16         58 *{_qualify_to_ref($class . '::' . $key)} = sub :lvalue {
1926             @_ > 1 ? $_[0]->{$key} = $_[1]
1927 16 100   16   223 : $_[0]->{$key};
1928 16         55 };
1929             }
1930             else {
1931 12         42 *{_qualify_to_ref($class . '::' . $key)} = sub {
1932 4     4   79 $_[0]->{$key};
1933 12         43 };
1934             };
1935             };
1936             };
1937              
1938 20         125 return $self;
1939             };
1940              
1941              
1942             =item package
1943              
1944             Returns the package name of the subroutine which thrown an exception.
1945              
1946             =item file
1947              
1948             Returns the file name of the subroutine which thrown an exception.
1949              
1950             =item line
1951              
1952             Returns the line number for file of the subroutine which thrown an exception.
1953              
1954             =item subroutine
1955              
1956             Returns the subroutine name which thrown an exception.
1957              
1958             =back
1959              
1960             =cut
1961              
1962             # Create caller_info() accessors for this class
1963             sub _make_caller_info_accessors {
1964 1     1   2 my ($self) = @_;
1965              
1966 1   33     6 my $class = ref $self || $self;
1967              
1968 1         2 foreach my $key (qw{ package file line subroutine }) {
1969 4 50       69 if (not $class->can($key)) {
1970 4         15 *{_qualify_to_ref($class . '::' . $key)} = sub {
1971 12     12   29 my $self = shift;
1972             my $ignore_level = defined $self->{ignore_level}
1973             ? $self->{ignore_level}
1974             : defined $self->{defaults}->{ignore_level}
1975             ? $self->{defaults}->{ignore_level}
1976 12 50       43 : 0;
    100          
1977 12         18 my $level = 0;
1978 12         29 while (my %c = $self->_caller_info($level++)) {
1979 24 100       54 next if $self->_skip_ignored_package($c{package});
1980             # Skip ignored levels
1981 20 100       44 if ($ignore_level > 0) {
1982 8         10 $ignore_level --;
1983 8         48 next;
1984             };
1985 12         71 return $c{$key};
1986             };
1987 4         28 };
1988             };
1989             };
1990              
1991 1         118 return $self;
1992             };
1993              
1994              
1995             # Load another module without eval q{}
1996             sub _load_package {
1997 28     28   45 my ($class, $package, $version) = @_;
1998              
1999 28 50       60 return unless $package;
2000              
2001 28         57 my $file = $package . '.pm';
2002 28         123 $file =~ s{::}{/}g;
2003              
2004 28         10826 require $file;
2005              
2006             # Check version if first element on list is a version number.
2007 4 50 33     133 if (defined $version and $version =~ m/^\d/) {
2008 4         68 $package->VERSION($version);
2009             };
2010              
2011 1         7 return $class;
2012             };
2013              
2014              
2015             # Create new exception class
2016             sub _make_exception {
2017 23     23   41 my ($class, $package, $version, $param) = @_;
2018              
2019 23 50       45 return unless $package;
2020              
2021 23 100       116 my $isa = defined $param->{isa} ? $param->{isa} : __PACKAGE__;
2022 23 100       51 $version = 0.01 if not $version;
2023              
2024 23 100       79 my $has = defined $param->{has} ? $param->{has} : { rw => [ ], ro => [ ] };
2025 23 100       71 if (ref $has eq 'ARRAY') {
    100          
2026 3         12 $has = { rw => $has, ro => [ ] };
2027             }
2028             elsif (not ref $has) {
2029 2         7 $has = { rw => [ $has ], ro => [ ] };
2030             };
2031 23         44 foreach my $mode ('rw', 'ro') {
2032 46 100       126 if (not ref $has->{$mode}) {
2033 6 100       24 $has->{$mode} = [ defined $has->{$mode} ? $has->{$mode} : () ];
2034             };
2035             };
2036              
2037             # Base class is needed
2038 23 100       27 if (not defined do { local $SIG{__DIE__}; eval { $isa->VERSION } }) {
  23         70  
  23         37  
  23         237  
2039 1         2 eval {
2040 1         3 $class->_load_package($isa);
2041             };
2042 1 50       6 if ($@) {
2043 1         4 Exception::Base->throw(
2044             message => ["Base class %s for class %s can not be found", $isa, $package],
2045             verbosity => 1
2046             );
2047             };
2048             };
2049              
2050             # Handle defaults for object attributes
2051 22         56 my $attributes;
2052             {
2053 22         23 local $SIG{__DIE__};
  22         57  
2054 22         28 eval {
2055 22         56 $attributes = $isa->ATTRS;
2056             };
2057             };
2058 22 50       65 if ($@) {
2059 0         0 Exception::Base->throw(
2060             message => ["%s class is based on %s class which does not implement ATTRS", $package, $isa],
2061             verbosity => 1
2062             );
2063             };
2064              
2065             # Create the hash with overridden attributes
2066 22         23 my %overridden_attributes;
2067             # Class => { has => { rw => [ "attr1", "attr2", "attr3", ... ], ro => [ "attr4", ... ] } }
2068 22         41 foreach my $mode ('rw', 'ro') {
2069 42         43 foreach my $attribute (@{ $has->{$mode} }) {
  42         179  
2070 12 100 66     99 if ($attribute =~ /^(isa|version|has)$/ or $isa->can($attribute)) {
2071 2         9 Exception::Base->throw(
2072             message => ["Attribute name `%s' can not be defined for %s class", $attribute, $package],
2073             );
2074             };
2075 10         37 $overridden_attributes{$attribute} = { is => $mode };
2076             };
2077             };
2078             # Class => { message => "overridden default", ... }
2079 20         28 foreach my $attribute (keys %{ $param }) {
  20         53  
2080 14 100       58 next if $attribute =~ /^(isa|version|has)$/;
2081 4 50 66     18 if (not exists $attributes->{$attribute}->{default}
2082             and not exists $overridden_attributes{$attribute})
2083             {
2084 1         5 Exception::Base->throw(
2085             message => ["%s class does not implement default value for `%s' attribute", $isa, $attribute],
2086             verbosity => 1
2087             );
2088             };
2089 3         7 $overridden_attributes{$attribute} = {};
2090 3         8 $overridden_attributes{$attribute}->{default} = $param->{$attribute};
2091 3         5 foreach my $property (keys %{ $attributes->{$attribute} }) {
  3         11  
2092 6 100       19 next if $property eq 'default';
2093 3         9 $overridden_attributes{$attribute}->{$property} = $attributes->{$attribute}->{$property};
2094             };
2095             };
2096              
2097             # Create the new package
2098 19         30 *{_qualify_to_ref("${package}::VERSION")} = \$version;
  19         69  
2099 19         335 *{_qualify_to_ref("${package}::ISA")} = [ $isa ];
  19         59  
2100 19         61 *{_qualify_to_ref("${package}::ATTRS")} = sub () {
2101 43     43   50 +{ %{ $isa->ATTRS }, %overridden_attributes };
  43         94  
2102 19         383 };
2103 19         365 $package->_make_accessors;
2104              
2105 19         99 return $class;
2106             };
2107              
2108              
2109             # Module initialization
2110             BEGIN {
2111 1     1   8 __PACKAGE__->_make_accessors;
2112 1         3 __PACKAGE__->_make_caller_info_accessors;
2113             };
2114              
2115              
2116             1;
2117              
2118              
2119             =begin plantuml
2120              
2121             class Exception::Base <> {
2122             +ignore_class : ArrayRef = []
2123             +ignore_level : Int = 0
2124             +ignore_package : ArrayRef = []
2125             +max_arg_len : Int = 64
2126             +max_arg_nums : Int = 8
2127             +max_eval_len : Int = 0
2128             +message : Str|ArrayRef[Str] = "Unknown exception"
2129             +value : Int = 0
2130             +verbosity : Int = 2
2131             ..
2132             +caller_stack : ArrayRef
2133             +egid : Int
2134             +euid : Int
2135             +gid : Int
2136             +pid : Int
2137             +propagated_stack : ArrayRef
2138             +tid : Int
2139             +time : Int
2140             +uid : Int
2141             ..
2142             #defaults : HashRef
2143             #default_attribute : Str = "message"
2144             #numeric_attribute : Str = "value"
2145             #eval_attribute : Str = "message"
2146             #string_attributes : ArrayRef[Str] = ["message"]
2147             ==
2148             +new( args : Hash ) <>
2149             +throw( args : Hash = undef ) <>
2150             +throw( message : Str, args : Hash = undef ) <>
2151             ..
2152             +catch() : Exception::Base
2153             +catch( variable : Any ) : Exception::Base
2154             +matches( that : Any ) : Bool {overload="~~"}
2155             +to_string() : Str {overload='""'}
2156             +to_number() : Num {overload="0+"}
2157             +to_bool() : Bool {overload="bool"}
2158             +get_caller_stacktrace() : Array[Str]|Str
2159             +PROPAGATE()
2160             ..
2161             +ATTRS() : HashRef <>
2162             ..
2163             #_collect_system_data()
2164             #_make_accessors() <>
2165             #_make_caller_info_accessors() <>
2166             }
2167              
2168             =end plantuml
2169              
2170             =head1 SEE ALSO
2171              
2172             Repository: L
2173              
2174             There are more implementation of exception objects available on CPAN. Please
2175             note that Perl has built-in implementation of pseudo-exceptions:
2176              
2177             eval { die { message => "Pseudo-exception", package => __PACKAGE__,
2178             file => __FILE__, line => __LINE__ };
2179             };
2180             if ($@) {
2181             print $@->{message}, " at ", $@->{file}, " in line ", $@->{line}, ".\n";
2182             }
2183              
2184             The more complex implementation of exception mechanism provides more features.
2185              
2186             =over
2187              
2188             =item L
2189              
2190             Complete implementation of try/catch/finally/otherwise mechanism. Uses nested
2191             closures with a lot of syntactic sugar. It is slightly faster than
2192             C module for failure scenario and is much slower for success
2193             scenario. It doesn't provide a simple way to create user defined exceptions.
2194             It doesn't collect system data and stack trace on error.
2195              
2196             =item L
2197              
2198             More Perlish way to do OO exceptions. It is similar to C
2199             module and provides similar features but it is 10x slower for failure
2200             scenario.
2201              
2202             =item L
2203              
2204             Additional try/catch mechanism for L. It is 15x slower for
2205             success scenario.
2206              
2207             =item L
2208              
2209             Elegant OO exceptions similar to L and C.
2210             It might be missing some features found in C and
2211             L.
2212              
2213             =item L
2214              
2215             Not recommended. Abandoned. Modifies C<%SIG> handlers.
2216              
2217             =item L
2218              
2219             A module which gives new try/catch keywords without source filter.
2220              
2221             =item L
2222              
2223             Smaller, simpler and slower version of L module.
2224              
2225             =back
2226              
2227             The C does not depend on other modules like
2228             L and it is more powerful than L. Also it
2229             does not use closures as L and does not pollute namespace as
2230             L. It is also much faster than
2231             L and L for success scenario.
2232              
2233             The C is compatible with syntax sugar modules like
2234             L and L.
2235              
2236             The C is also a base class for enhanced classes:
2237              
2238             =over
2239              
2240             =item L
2241              
2242             The exception class for system or library calls which modifies C<$!> variable.
2243              
2244             =item L
2245              
2246             The exception class for eval blocks with simple L. It can also
2247             handle L<$SIG{__DIE__}|perlvar/%SIG> hook and convert simple L
2248             into an exception object.
2249              
2250             =item L
2251              
2252             The exception class which handle L<$SIG{__WARN__}|pervar/%SIG> hook and
2253             convert simple L into an exception object.
2254              
2255             =back
2256              
2257             =head1 EXAMPLES
2258              
2259             =head2 New exception classes
2260              
2261             The C module allows to create new exception classes easily.
2262             You can use L interface or L module to do it.
2263              
2264             The L interface allows to create new class with new
2265             read-write attributes.
2266              
2267             package Exception::Simple;
2268             use Exception::Base (__PACKAGE__) => {
2269             has => qw{ reason method },
2270             string_attributes => qw{ message reason method },
2271             };
2272              
2273             For more complex exceptions you can redefine C constant.
2274              
2275             package Exception::Complex;
2276             use base 'Exception::Base';
2277             use constant ATTRS => {
2278             %{ Exception::Base->ATTRS }, # SUPER::ATTRS
2279             hostname => { is => 'ro' },
2280             string_attributes => qw{ hostname message },
2281             };
2282             sub _collect_system_data {
2283             my $self = shift;
2284             my $hostname = `hostname`;
2285             chomp $hostname;
2286             $self->{hostname} = $hostname;
2287             return $self->SUPER::_collect_system_data(@_);
2288             }
2289              
2290             =head1 PERFORMANCE
2291              
2292             There are two scenarios for L block: success or failure.
2293             Success scenario should have no penalty on speed. Failure scenario is usually
2294             more complex to handle and can be significantly slower.
2295              
2296             Any other code than simple C is really slow and shouldn't be used if
2297             speed is important. It means that any module which provides try/catch syntax
2298             sugar should be avoided: L, L, L,
2299             L. Be careful because simple C has many gotchas which are
2300             described in L's documentation.
2301              
2302             The C module was benchmarked with other implementations for
2303             simple try/catch scenario. The results
2304             (Perl 5.10.1 x86_64-linux-thread-multi) are following:
2305              
2306             -----------------------------------------------------------------------
2307             | Module | Success sub/s | Failure sub/s |
2308             -----------------------------------------------------------------------
2309             | eval/die string | 3715708 | 408951 |
2310             -----------------------------------------------------------------------
2311             | eval/die object | 4563524 | 191664 |
2312             -----------------------------------------------------------------------
2313             | Exception::Base eval/if | 4903857 | 11291 |
2314             -----------------------------------------------------------------------
2315             | Exception::Base eval/if verbosity=1 | 4790762 | 18833 |
2316             -----------------------------------------------------------------------
2317             | Error | 117475 | 26694 |
2318             -----------------------------------------------------------------------
2319             | Class::Throwable | 4618545 | 12678 |
2320             -----------------------------------------------------------------------
2321             | Exception::Class | 643901 | 3493 |
2322             -----------------------------------------------------------------------
2323             | Exception::Class::TryCatch | 307825 | 3439 |
2324             -----------------------------------------------------------------------
2325             | TryCatch | 690784 | 294802 |
2326             -----------------------------------------------------------------------
2327             | Try::Tiny | 268780 | 158383 |
2328             -----------------------------------------------------------------------
2329              
2330             The C module was written to be as fast as it is
2331             possible. It does not use internally i.e. accessor functions which are
2332             slower about 6 times than standard variables. It is slower than pure
2333             die/eval for success scenario because it is uses OO mechanisms which are slow
2334             in Perl. It can be a little faster if some features are disables, i.e. the
2335             stack trace and higher verbosity.
2336              
2337             You can find the benchmark script in this package distribution.
2338              
2339             =head1 BUGS
2340              
2341             If you find the bug or want to implement new features, please report it at
2342             L
2343              
2344             The code repository is available at
2345             L
2346              
2347             =for readme continue
2348              
2349             =head1 AUTHOR
2350              
2351             Piotr Roszatycki
2352              
2353             =head1 LICENSE
2354              
2355             Copyright (c) 2007-2015 Piotr Roszatycki .
2356              
2357             This program is free software; you can redistribute it and/or modify it
2358             under the same terms as Perl itself.
2359              
2360             See L