| Filename | /home/ss5/perl5/perlbrew/perls/perl-5.14.1/lib/site_perl/5.14.1/Exception/Class.pm |
| Statements | Executed 263 statements in 8.63ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 6.03ms | 29.1ms | Exception::Class::BEGIN@10 |
| 8 | 1 | 1 | 3.43ms | 6.92ms | Exception::Class::_make_subclass |
| 1 | 1 | 1 | 428µs | 7.40ms | Exception::Class::import |
| 1 | 1 | 1 | 67µs | 67µs | Exception::Class::BEGIN@6 |
| 8 | 1 | 1 | 62µs | 62µs | Exception::Class::CORE:subst (opcode) |
| 1 | 1 | 1 | 52µs | 52µs | Exception::Class::CORE:sort (opcode) |
| 1 | 1 | 1 | 38µs | 186µs | Exception::Class::BEGIN@11 |
| 1 | 1 | 1 | 36µs | 79µs | Exception::Class::BEGIN@176 |
| 1 | 1 | 1 | 34µs | 34µs | Exception::Class::BEGIN@2 |
| 1 | 1 | 1 | 34µs | 82µs | Exception::Class::BEGIN@168 |
| 1 | 1 | 1 | 28µs | 41µs | Exception::Class::BEGIN@8 |
| 1 | 1 | 1 | 27µs | 78µs | Exception::Class::BEGIN@46 |
| 1 | 1 | 1 | 26µs | 64µs | Exception::Class::BEGIN@79 |
| 1 | 1 | 1 | 15µs | 15µs | Exception::Class::BEGIN@14 |
| 2 | 1 | 1 | 14µs | 14µs | Exception::Class::CORE:substcont (opcode) |
| 0 | 0 | 0 | 0s | 0s | Exception::Class::Classes |
| 0 | 0 | 0 | 0s | 0s | Exception::Class::__ANON__[:170] |
| 0 | 0 | 0 | 0s | 0s | Exception::Class::_make_parents |
| 0 | 0 | 0 | 0s | 0s | Exception::Class::caught |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Exception::Class; | ||||
| 2 | # spent 34µs within Exception::Class::BEGIN@2 which was called:
# once (34µs+0s) by Iterator::BEGIN@22 at line 4 | ||||
| 3 | 1 | 31µs | $Exception::Class::VERSION = '1.32'; | ||
| 4 | 1 | 79µs | 1 | 34µs | } # spent 34µs making 1 call to Exception::Class::BEGIN@2 |
| 5 | |||||
| 6 | 2 | 194µs | 1 | 67µs | # spent 67µs within Exception::Class::BEGIN@6 which was called:
# once (67µs+0s) by Iterator::BEGIN@22 at line 6 # spent 67µs making 1 call to Exception::Class::BEGIN@6 |
| 7 | |||||
| 8 | 2 | 93µs | 2 | 54µs | # spent 41µs (28+13) within Exception::Class::BEGIN@8 which was called:
# once (28µs+13µs) by Iterator::BEGIN@22 at line 8 # spent 41µs making 1 call to Exception::Class::BEGIN@8
# spent 13µs making 1 call to strict::import |
| 9 | |||||
| 10 | 2 | 440µs | 1 | 29.1ms | # spent 29.1ms (6.03+23.0) within Exception::Class::BEGIN@10 which was called:
# once (6.03ms+23.0ms) by Iterator::BEGIN@22 at line 10 # spent 29.1ms making 1 call to Exception::Class::BEGIN@10 |
| 11 | 2 | 180µs | 2 | 335µs | # spent 186µs (38+148) within Exception::Class::BEGIN@11 which was called:
# once (38µs+148µs) by Iterator::BEGIN@22 at line 11 # spent 186µs making 1 call to Exception::Class::BEGIN@11
# spent 148µs making 1 call to Exporter::import |
| 12 | |||||
| 13 | 1 | 800ns | our $BASE_EXC_CLASS; | ||
| 14 | 1 | 537µs | 1 | 15µs | # spent 15µs within Exception::Class::BEGIN@14 which was called:
# once (15µs+0s) by Iterator::BEGIN@22 at line 14 # spent 15µs making 1 call to Exception::Class::BEGIN@14 |
| 15 | |||||
| 16 | 1 | 900ns | our %CLASSES; | ||
| 17 | |||||
| 18 | # spent 7.40ms (428µs+6.98) within Exception::Class::import which was called:
# once (428µs+6.98ms) by Iterator::BEGIN@22 at line 23 of Iterator.pm | ||||
| 19 | 1 | 3µs | my $class = shift; | ||
| 20 | |||||
| 21 | 1 | 4µs | local $Exception::Class::Caller = caller(); | ||
| 22 | |||||
| 23 | 1 | 1µs | my %c; | ||
| 24 | |||||
| 25 | 1 | 700ns | my %needs_parent; | ||
| 26 | 1 | 21µs | while ( my $subclass = shift ) { | ||
| 27 | 8 | 13µs | my $def = ref $_[0] ? shift : {}; | ||
| 28 | 8 | 38µs | $def->{isa} | ||
| 29 | = $def->{isa} | ||||
| 30 | ? ( ref $def->{isa} ? $def->{isa} : [ $def->{isa} ] ) | ||||
| 31 | : []; | ||||
| 32 | |||||
| 33 | 8 | 26µs | $c{$subclass} = $def; | ||
| 34 | } | ||||
| 35 | |||||
| 36 | # We need to sort by length because if we check for keys in the | ||||
| 37 | # Foo::Bar:: stash, this creates a "Bar::" key in the Foo:: stash! | ||||
| 38 | MAKE_CLASSES: | ||||
| 39 | 1 | 92µs | 1 | 52µs | foreach my $subclass ( sort { length $a <=> length $b } keys %c ) { # spent 52µs making 1 call to Exception::Class::CORE:sort |
| 40 | 8 | 19µs | my $def = $c{$subclass}; | ||
| 41 | |||||
| 42 | # We already made this one. | ||||
| 43 | 8 | 15µs | next if $CLASSES{$subclass}; | ||
| 44 | |||||
| 45 | { | ||||
| 46 | 10 | 668µs | 2 | 129µs | # spent 78µs (27+51) within Exception::Class::BEGIN@46 which was called:
# once (27µs+51µs) by Iterator::BEGIN@22 at line 46 # spent 78µs making 1 call to Exception::Class::BEGIN@46
# spent 51µs making 1 call to strict::unimport |
| 47 | 8 | 38µs | foreach my $parent ( @{ $def->{isa} } ) { | ||
| 48 | 7 | 52µs | unless ( keys %{"$parent\::"} ) { | ||
| 49 | $needs_parent{$subclass} = { | ||||
| 50 | parents => $def->{isa}, | ||||
| 51 | def => $def | ||||
| 52 | }; | ||||
| 53 | next MAKE_CLASSES; | ||||
| 54 | } | ||||
| 55 | } | ||||
| 56 | } | ||||
| 57 | |||||
| 58 | $class->_make_subclass( | ||||
| 59 | 8 | 85µs | 8 | 6.92ms | subclass => $subclass, # spent 6.92ms making 8 calls to Exception::Class::_make_subclass, avg 865µs/call |
| 60 | def => $def || {}, | ||||
| 61 | ); | ||||
| 62 | } | ||||
| 63 | |||||
| 64 | 1 | 25µs | foreach my $subclass ( keys %needs_parent ) { | ||
| 65 | |||||
| 66 | # This will be used to spot circular references. | ||||
| 67 | my %seen; | ||||
| 68 | $class->_make_parents( \%needs_parent, $subclass, \%seen ); | ||||
| 69 | } | ||||
| 70 | } | ||||
| 71 | |||||
| 72 | sub _make_parents { | ||||
| 73 | my $class = shift; | ||||
| 74 | my $needs = shift; | ||||
| 75 | my $subclass = shift; | ||||
| 76 | my $seen = shift; | ||||
| 77 | my $child = shift; # Just for error messages. | ||||
| 78 | |||||
| 79 | 2 | 1.66ms | 2 | 102µs | # spent 64µs (26+38) within Exception::Class::BEGIN@79 which was called:
# once (26µs+38µs) by Iterator::BEGIN@22 at line 79 # spent 64µs making 1 call to Exception::Class::BEGIN@79
# spent 38µs making 1 call to strict::unimport |
| 80 | |||||
| 81 | # What if someone makes a typo in specifying their 'isa' param? | ||||
| 82 | # This should catch it. Either it's been made because it didn't | ||||
| 83 | # have missing parents OR it's in our hash as needing a parent. | ||||
| 84 | # If neither of these is true then the _only_ place it is | ||||
| 85 | # mentioned is in the 'isa' param for some other class, which is | ||||
| 86 | # not a good enough reason to make a new class. | ||||
| 87 | die | ||||
| 88 | "Class $subclass appears to be a typo as it is only specified in the 'isa' param for $child\n" | ||||
| 89 | unless exists $needs->{$subclass} | ||||
| 90 | || $CLASSES{$subclass} | ||||
| 91 | || keys %{"$subclass\::"}; | ||||
| 92 | |||||
| 93 | foreach my $c ( @{ $needs->{$subclass}{parents} } ) { | ||||
| 94 | |||||
| 95 | # It's been made | ||||
| 96 | next if $CLASSES{$c} || keys %{"$c\::"}; | ||||
| 97 | |||||
| 98 | die "There appears to be some circularity involving $subclass\n" | ||||
| 99 | if $seen->{$subclass}; | ||||
| 100 | |||||
| 101 | $seen->{$subclass} = 1; | ||||
| 102 | |||||
| 103 | $class->_make_parents( $needs, $c, $seen, $subclass ); | ||||
| 104 | } | ||||
| 105 | |||||
| 106 | return if $CLASSES{$subclass} || keys %{"$subclass\::"}; | ||||
| 107 | |||||
| 108 | $class->_make_subclass( | ||||
| 109 | subclass => $subclass, | ||||
| 110 | def => $needs->{$subclass}{def} | ||||
| 111 | ); | ||||
| 112 | } | ||||
| 113 | |||||
| 114 | # spent 6.92ms (3.43+3.49) within Exception::Class::_make_subclass which was called 8 times, avg 865µs/call:
# 8 times (3.43ms+3.49ms) by Exception::Class::import at line 59, avg 865µs/call | ||||
| 115 | 8 | 11µs | my $class = shift; | ||
| 116 | 8 | 45µs | my %p = @_; | ||
| 117 | |||||
| 118 | 8 | 15µs | my $subclass = $p{subclass}; | ||
| 119 | 8 | 9µs | my $def = $p{def}; | ||
| 120 | |||||
| 121 | 8 | 4µs | my $isa; | ||
| 122 | 8 | 46µs | if ( $def->{isa} ) { | ||
| 123 | $isa = ref $def->{isa} ? join ' ', @{ $def->{isa} } : $def->{isa}; | ||||
| 124 | } | ||||
| 125 | 8 | 6µs | $isa ||= $BASE_EXC_CLASS; | ||
| 126 | |||||
| 127 | 8 | 8µs | my $version_name = 'VERSION'; | ||
| 128 | |||||
| 129 | 8 | 28µs | my $code = <<"EOPERL"; | ||
| 130 | package $subclass; | ||||
| 131 | |||||
| 132 | use base qw($isa); | ||||
| 133 | |||||
| 134 | our \$$version_name = '1.1'; | ||||
| 135 | |||||
| 136 | 1; | ||||
| 137 | |||||
| 138 | EOPERL | ||||
| 139 | |||||
| 140 | 8 | 18µs | if ( $def->{description} ) { | ||
| 141 | 8 | 194µs | 10 | 76µs | ( my $desc = $def->{description} ) =~ s/([\\\'])/\\$1/g; # spent 62µs making 8 calls to Exception::Class::CORE:subst, avg 8µs/call
# spent 14µs making 2 calls to Exception::Class::CORE:substcont, avg 7µs/call |
| 142 | 8 | 33µs | $code .= <<"EOPERL"; | ||
| 143 | sub description | ||||
| 144 | { | ||||
| 145 | return '$desc'; | ||||
| 146 | } | ||||
| 147 | EOPERL | ||||
| 148 | } | ||||
| 149 | |||||
| 150 | 8 | 6µs | my @fields; | ||
| 151 | 8 | 22µs | if ( my $fields = $def->{fields} ) { | ||
| 152 | 3 | 56µs | 3 | 19µs | @fields = UNIVERSAL::isa( $fields, 'ARRAY' ) ? @$fields : $fields; # spent 19µs making 3 calls to UNIVERSAL::isa, avg 6µs/call |
| 153 | |||||
| 154 | $code | ||||
| 155 | .= "sub Fields { return (\$_[0]->SUPER::Fields, " | ||||
| 156 | 3 | 31µs | . join( ", ", map {"'$_'"} @fields ) | ||
| 157 | . ") }\n\n"; | ||||
| 158 | |||||
| 159 | 3 | 9µs | foreach my $field (@fields) { | ||
| 160 | 3 | 30µs | $code .= sprintf( "sub %s { \$_[0]->{%s} }\n", $field, $field ); | ||
| 161 | } | ||||
| 162 | } | ||||
| 163 | |||||
| 164 | 8 | 15µs | if ( my $alias = $def->{alias} ) { | ||
| 165 | die "Cannot make alias without caller" | ||||
| 166 | unless defined $Exception::Class::Caller; | ||||
| 167 | |||||
| 168 | 2 | 499µs | 2 | 130µs | # spent 82µs (34+48) within Exception::Class::BEGIN@168 which was called:
# once (34µs+48µs) by Iterator::BEGIN@22 at line 168 # spent 82µs making 1 call to Exception::Class::BEGIN@168
# spent 48µs making 1 call to strict::unimport |
| 169 | *{"$Exception::Class::Caller\::$alias"} | ||||
| 170 | = sub { $subclass->throw(@_) }; | ||||
| 171 | } | ||||
| 172 | |||||
| 173 | 8 | 10µs | if ( my $defaults = $def->{defaults} ) { | ||
| 174 | $code | ||||
| 175 | .= "sub _defaults { return shift->SUPER::_defaults, our \%_DEFAULTS }\n"; | ||||
| 176 | 2 | 1.66ms | 2 | 122µs | # spent 79µs (36+43) within Exception::Class::BEGIN@176 which was called:
# once (36µs+43µs) by Iterator::BEGIN@22 at line 176 # spent 79µs making 1 call to Exception::Class::BEGIN@176
# spent 43µs making 1 call to strict::unimport |
| 177 | *{"$subclass\::_DEFAULTS"} = {%$defaults}; | ||||
| 178 | } | ||||
| 179 | |||||
| 180 | 8 | 1.40ms | eval $code; # spent 299µs executing statements in string eval # includes 37µs spent executing 1 call to 4 subs defined therein. # spent 296µs executing statements in string eval # includes 57µs spent executing 1 call to 4 subs defined therein. # spent 290µs executing statements in string eval # includes 44µs spent executing 1 call to 4 subs defined therein. # spent 195µs executing statements in string eval # includes 41µs spent executing 1 call to 2 subs defined therein. # spent 171µs executing statements in string eval # includes 46µs spent executing 1 call to 2 subs defined therein. # spent 161µs executing statements in string eval # includes 41µs spent executing 1 call to 2 subs defined therein. # spent 153µs executing statements in string eval # includes 60µs spent executing 1 call to 2 subs defined therein. # spent 149µs executing statements in string eval # includes 39µs spent executing 1 call to 2 subs defined therein. | ||
| 181 | |||||
| 182 | 8 | 6µs | die $@ if $@; | ||
| 183 | |||||
| 184 | 8 | 148µs | $CLASSES{$subclass} = 1; | ||
| 185 | } | ||||
| 186 | |||||
| 187 | sub caught { | ||||
| 188 | my $e = $@; | ||||
| 189 | |||||
| 190 | return $e unless $_[1]; | ||||
| 191 | |||||
| 192 | return unless blessed($e) && $e->isa( $_[1] ); | ||||
| 193 | return $e; | ||||
| 194 | } | ||||
| 195 | |||||
| 196 | sub Classes { sort keys %Exception::Class::CLASSES } | ||||
| 197 | |||||
| 198 | 1 | 13µs | 1; | ||
| 199 | |||||
| 200 | # ABSTRACT: A module that allows you to declare real exception classes in Perl | ||||
| 201 | |||||
| - - | |||||
| 204 | =pod | ||||
| 205 | |||||
| 206 | =head1 NAME | ||||
| 207 | |||||
| 208 | Exception::Class - A module that allows you to declare real exception classes in Perl | ||||
| 209 | |||||
| 210 | =head1 VERSION | ||||
| 211 | |||||
| 212 | version 1.32 | ||||
| 213 | |||||
| 214 | =head1 SYNOPSIS | ||||
| 215 | |||||
| 216 | use Exception::Class ( | ||||
| 217 | 'MyException', | ||||
| 218 | |||||
| 219 | 'AnotherException' => { isa => 'MyException' }, | ||||
| 220 | |||||
| 221 | 'YetAnotherException' => { | ||||
| 222 | isa => 'AnotherException', | ||||
| 223 | description => 'These exceptions are related to IPC' | ||||
| 224 | }, | ||||
| 225 | |||||
| 226 | 'ExceptionWithFields' => { | ||||
| 227 | isa => 'YetAnotherException', | ||||
| 228 | fields => [ 'grandiosity', 'quixotic' ], | ||||
| 229 | alias => 'throw_fields', | ||||
| 230 | }, | ||||
| 231 | ); | ||||
| 232 | |||||
| 233 | # try | ||||
| 234 | eval { MyException->throw( error => 'I feel funny.' ) }; | ||||
| 235 | |||||
| 236 | my $e; | ||||
| 237 | |||||
| 238 | # catch | ||||
| 239 | if ( $e = Exception::Class->caught('MyException') ) { | ||||
| 240 | warn $e->error, "\n", $e->trace->as_string, "\n"; | ||||
| 241 | warn join ' ', $e->euid, $e->egid, $e->uid, $e->gid, $e->pid, $e->time; | ||||
| 242 | |||||
| 243 | exit; | ||||
| 244 | } | ||||
| 245 | elsif ( $e = Exception::Class->caught('ExceptionWithFields') ) { | ||||
| 246 | $e->quixotic ? do_something_wacky() : do_something_sane(); | ||||
| 247 | } | ||||
| 248 | else { | ||||
| 249 | $e = Exception::Class->caught(); | ||||
| 250 | ref $e ? $e->rethrow : die $e; | ||||
| 251 | } | ||||
| 252 | |||||
| 253 | # use an alias - without parens subroutine name is checked at | ||||
| 254 | # compile time | ||||
| 255 | throw_fields error => "No strawberry", grandiosity => "quite a bit"; | ||||
| 256 | |||||
| 257 | =head1 DESCRIPTION | ||||
| 258 | |||||
| 259 | Exception::Class allows you to declare exception hierarchies in your | ||||
| 260 | modules in a "Java-esque" manner. | ||||
| 261 | |||||
| 262 | It features a simple interface allowing programmers to 'declare' | ||||
| 263 | exception classes at compile time. It also has a base exception | ||||
| 264 | class, L<Exception::Class::Base>, that can be easily extended. | ||||
| 265 | |||||
| 266 | It is designed to make structured exception handling simpler and | ||||
| 267 | better by encouraging people to use hierarchies of exceptions in their | ||||
| 268 | applications, as opposed to a single catch-all exception class. | ||||
| 269 | |||||
| 270 | This module does not implement any try/catch syntax. Please see the | ||||
| 271 | "OTHER EXCEPTION MODULES (try/catch syntax)" section for more | ||||
| 272 | information on how to get this syntax. | ||||
| 273 | |||||
| 274 | You will also want to look at the documentation for | ||||
| 275 | L<Exception::Class::Base>, which is the default base class for all | ||||
| 276 | exception objects created by this module. | ||||
| 277 | |||||
| 278 | =head1 DECLARING EXCEPTION CLASSES | ||||
| 279 | |||||
| 280 | Importing C<Exception::Class> allows you to automagically create | ||||
| 281 | L<Exception::Class::Base> subclasses. You can also create subclasses | ||||
| 282 | via the traditional means of defining your own subclass with C<@ISA>. | ||||
| 283 | These two methods may be easily combined, so that you could subclass | ||||
| 284 | an exception class defined via the automagic import, if you desired | ||||
| 285 | this. | ||||
| 286 | |||||
| 287 | The syntax for the magic declarations is as follows: | ||||
| 288 | |||||
| 289 | 'MANDATORY CLASS NAME' => \%optional_hashref | ||||
| 290 | |||||
| 291 | The hashref may contain the following options: | ||||
| 292 | |||||
| 293 | =over 4 | ||||
| 294 | |||||
| 295 | =item * isa | ||||
| 296 | |||||
| 297 | This is the class's parent class. If this isn't provided then the | ||||
| 298 | class name in C<$Exception::Class::BASE_EXC_CLASS> is assumed to be | ||||
| 299 | the parent (see below). | ||||
| 300 | |||||
| 301 | This parameter lets you create arbitrarily deep class hierarchies. | ||||
| 302 | This can be any other L<Exception::Class::Base> subclass in your | ||||
| 303 | declaration I<or> a subclass loaded from a module. | ||||
| 304 | |||||
| 305 | To change the default exception class you will need to change the | ||||
| 306 | value of C<$Exception::Class::BASE_EXC_CLASS> I<before> calling | ||||
| 307 | C<import()>. To do this simply do something like this: | ||||
| 308 | |||||
| 309 | BEGIN { $Exception::Class::BASE_EXC_CLASS = 'SomeExceptionClass'; } | ||||
| 310 | |||||
| 311 | If anyone can come up with a more elegant way to do this please let me | ||||
| 312 | know. | ||||
| 313 | |||||
| 314 | CAVEAT: If you want to automagically subclass an | ||||
| 315 | L<Exception::Class::Base> subclass loaded from a file, then you | ||||
| 316 | I<must> compile the class (via use or require or some other magic) | ||||
| 317 | I<before> you import C<Exception::Class> or you'll get a compile time | ||||
| 318 | error. | ||||
| 319 | |||||
| 320 | =item * fields | ||||
| 321 | |||||
| 322 | This allows you to define additional attributes for your exception | ||||
| 323 | class. Any field you define can be passed to the C<throw()> or | ||||
| 324 | C<new()> methods as additional parameters for the constructor. In | ||||
| 325 | addition, your exception object will have an accessor method for the | ||||
| 326 | fields you define. | ||||
| 327 | |||||
| 328 | This parameter can be either a scalar (for a single field) or an array | ||||
| 329 | reference if you need to define multiple fields. | ||||
| 330 | |||||
| 331 | Fields will be inherited by subclasses. | ||||
| 332 | |||||
| 333 | =item * alias | ||||
| 334 | |||||
| 335 | Specifying an alias causes this class to create a subroutine of the | ||||
| 336 | specified name in the I<caller's> namespace. Calling this subroutine | ||||
| 337 | is equivalent to calling C<< <class>->throw(@_) >> for the given | ||||
| 338 | exception class. | ||||
| 339 | |||||
| 340 | Besides convenience, using aliases also allows for additional compile | ||||
| 341 | time checking. If the alias is called I<without parentheses>, as in | ||||
| 342 | C<throw_fields "an error occurred">, then Perl checks for the | ||||
| 343 | existence of the C<throw_fields()> subroutine at compile time. If | ||||
| 344 | instead you do C<< ExceptionWithFields->throw(...) >>, then Perl | ||||
| 345 | checks the class name at runtime, meaning that typos may sneak | ||||
| 346 | through. | ||||
| 347 | |||||
| 348 | =item * description | ||||
| 349 | |||||
| 350 | Each exception class has a description method that returns a fixed | ||||
| 351 | string. This should describe the exception I<class> (as opposed to | ||||
| 352 | any particular exception object). This may be useful for debugging if | ||||
| 353 | you start catching exceptions you weren't expecting (particularly if | ||||
| 354 | someone forgot to document them) and you don't understand the error | ||||
| 355 | messages. | ||||
| 356 | |||||
| 357 | =back | ||||
| 358 | |||||
| 359 | The C<Exception::Class> magic attempts to detect circular class | ||||
| 360 | hierarchies and will die if it finds one. It also detects missing | ||||
| 361 | links in a chain, for example if you declare Bar to be a subclass of | ||||
| 362 | Foo and never declare Foo. | ||||
| 363 | |||||
| 364 | =head1 Catching Exceptions | ||||
| 365 | |||||
| 366 | C<Exception::Class> provides some syntactic sugar for catching | ||||
| 367 | exceptions in a safe manner: | ||||
| 368 | |||||
| 369 | eval {...}; | ||||
| 370 | |||||
| 371 | if ( my $e = Exception::Class->caught('My::Error') ) { | ||||
| 372 | cleanup(); | ||||
| 373 | do_something_with_exception($e); | ||||
| 374 | } | ||||
| 375 | |||||
| 376 | The C<caught()> method takes a class name and returns an exception | ||||
| 377 | object if the last thrown exception is of the given class, or a | ||||
| 378 | subclass of that class. If it is not given any arguments, it simply | ||||
| 379 | returns C<$@>. | ||||
| 380 | |||||
| 381 | You should B<always> make a copy of the exception object, rather than | ||||
| 382 | using C<$@> directly. This is necessary because if your C<cleanup()> | ||||
| 383 | function uses C<eval>, or calls something which uses it, then C<$@> is | ||||
| 384 | overwritten. Copying the exception preserves it for the call to | ||||
| 385 | C<do_something_with_exception()>. | ||||
| 386 | |||||
| 387 | Exception objects also provide a caught method so you can write: | ||||
| 388 | |||||
| 389 | if ( my $e = My::Error->caught() ) { | ||||
| 390 | cleanup(); | ||||
| 391 | do_something_with_exception($e); | ||||
| 392 | } | ||||
| 393 | |||||
| 394 | =head2 Uncatchable Exceptions | ||||
| 395 | |||||
| 396 | Internally, the C<caught()> method will call C<isa()> on the exception | ||||
| 397 | object. You could make an exception "uncatchable" by overriding | ||||
| 398 | C<isa()> in that class like this: | ||||
| 399 | |||||
| 400 | package Exception::Uncatchable; | ||||
| 401 | |||||
| 402 | sub isa { shift->rethrow } | ||||
| 403 | |||||
| 404 | Of course, this only works if you always call | ||||
| 405 | C<< Exception::Class->caught() >> after an C<eval>. | ||||
| 406 | |||||
| 407 | =head1 USAGE RECOMMENDATION | ||||
| 408 | |||||
| 409 | If you're creating a complex system that throws lots of different | ||||
| 410 | types of exceptions, consider putting all the exception declarations | ||||
| 411 | in one place. For an app called Foo you might make a | ||||
| 412 | C<Foo::Exceptions> module and use that in all your code. This module | ||||
| 413 | could just contain the code to make C<Exception::Class> do its | ||||
| 414 | automagic class creation. Doing this allows you to more easily see | ||||
| 415 | what exceptions you have, and makes it easier to keep track of them. | ||||
| 416 | |||||
| 417 | This might look something like this: | ||||
| 418 | |||||
| 419 | package Foo::Bar::Exceptions; | ||||
| 420 | |||||
| 421 | use Exception::Class ( | ||||
| 422 | Foo::Bar::Exception::Senses => | ||||
| 423 | { description => 'sense-related exception' }, | ||||
| 424 | |||||
| 425 | Foo::Bar::Exception::Smell => { | ||||
| 426 | isa => 'Foo::Bar::Exception::Senses', | ||||
| 427 | fields => 'odor', | ||||
| 428 | description => 'stinky!' | ||||
| 429 | }, | ||||
| 430 | |||||
| 431 | Foo::Bar::Exception::Taste => { | ||||
| 432 | isa => 'Foo::Bar::Exception::Senses', | ||||
| 433 | fields => [ 'taste', 'bitterness' ], | ||||
| 434 | description => 'like, gag me with a spoon!' | ||||
| 435 | }, | ||||
| 436 | |||||
| 437 | ... | ||||
| 438 | ); | ||||
| 439 | |||||
| 440 | You may want to create a real module to subclass | ||||
| 441 | L<Exception::Class::Base> as well, particularly if you want your | ||||
| 442 | exceptions to have more methods. | ||||
| 443 | |||||
| 444 | =head2 Subclassing Exception::Class::Base | ||||
| 445 | |||||
| 446 | As part of your usage of C<Exception::Class>, you may want to create | ||||
| 447 | your own base exception class which subclasses | ||||
| 448 | L<Exception::Class::Base>. You should feel free to subclass any of | ||||
| 449 | the methods documented above. For example, you may want to subclass | ||||
| 450 | C<new()> to add additional information to your exception objects. | ||||
| 451 | |||||
| 452 | =head1 Exception::Class FUNCTIONS | ||||
| 453 | |||||
| 454 | The C<Exception::Class> method offers one function, C<Classes()>, | ||||
| 455 | which is not exported. This method returns a list of the classes that | ||||
| 456 | have been created by calling the C<Exception::Class> import() method. | ||||
| 457 | Note that this is I<all> the subclasses that have been created, so it | ||||
| 458 | may include subclasses created by things like CPAN modules, etc. Also | ||||
| 459 | note that if you simply define a subclass via the normal Perl method | ||||
| 460 | of setting C<@ISA> or C<use base>, then your subclass will not be | ||||
| 461 | included. | ||||
| 462 | |||||
| 463 | =head1 OTHER EXCEPTION MODULES (try/catch syntax) | ||||
| 464 | |||||
| 465 | If you are interested in adding try/catch/finally syntactic sugar to | ||||
| 466 | your code then I recommend you check out U. Arun Kumar's C<Error.pm> | ||||
| 467 | module, which implements this syntax. It also includes its own base | ||||
| 468 | exception class, C<Error::Simple>. | ||||
| 469 | |||||
| 470 | If you would prefer to use the L<Exception::Class::Base> class | ||||
| 471 | included with this module, you'll have to add this to your code | ||||
| 472 | somewhere: | ||||
| 473 | |||||
| 474 | push @Exception::Class::Base::ISA, 'Error' | ||||
| 475 | unless Exception::Class::Base->isa('Error'); | ||||
| 476 | |||||
| 477 | It's a hack but apparently it works. | ||||
| 478 | |||||
| 479 | =head1 SUPPORT | ||||
| 480 | |||||
| 481 | Please submit bugs to the CPAN RT system at | ||||
| 482 | http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Exception%3A%3AClass or | ||||
| 483 | via email at bug-exception-class@rt.cpan.org. | ||||
| 484 | |||||
| 485 | =head1 DONATIONS | ||||
| 486 | |||||
| 487 | If you'd like to thank me for the work I've done on this module, | ||||
| 488 | please consider making a "donation" to me via PayPal. I spend a lot of | ||||
| 489 | free time creating free software, and would appreciate any support | ||||
| 490 | you'd care to offer. | ||||
| 491 | |||||
| 492 | Please note that B<I am not suggesting that you must do this> in order | ||||
| 493 | for me to continue working on this particular software. I will | ||||
| 494 | continue to do so, inasmuch as I have in the past, for as long as it | ||||
| 495 | interests me. | ||||
| 496 | |||||
| 497 | Similarly, a donation made in this way will probably not make me work | ||||
| 498 | on this software much more, unless I get so many donations that I can | ||||
| 499 | consider working on free software full time, which seems unlikely at | ||||
| 500 | best. | ||||
| 501 | |||||
| 502 | To donate, log into PayPal and send money to autarch@urth.org or use | ||||
| 503 | the button on this page: | ||||
| 504 | L<http://www.urth.org/~autarch/fs-donation.html> | ||||
| 505 | |||||
| 506 | =head1 AUTHOR | ||||
| 507 | |||||
| 508 | Dave Rolsky <autarch@urth.org> | ||||
| 509 | |||||
| 510 | =head1 COPYRIGHT AND LICENSE | ||||
| 511 | |||||
| 512 | This software is Copyright (c) 2010 by Dave Rolsky. | ||||
| 513 | |||||
| 514 | This is free software, licensed under: | ||||
| 515 | |||||
| 516 | The Artistic License 2.0 | ||||
| 517 | |||||
| 518 | =cut | ||||
| 519 | |||||
| 520 | |||||
| 521 | __END__ | ||||
# spent 52µs within Exception::Class::CORE:sort which was called:
# once (52µs+0s) by Exception::Class::import at line 39 | |||||
# spent 62µs within Exception::Class::CORE:subst which was called 8 times, avg 8µs/call:
# 8 times (62µs+0s) by Exception::Class::_make_subclass at line 141, avg 8µs/call | |||||
# spent 14µs within Exception::Class::CORE:substcont which was called 2 times, avg 7µs/call:
# 2 times (14µs+0s) by Exception::Class::_make_subclass at line 141, avg 7µs/call |