File Coverage

lib/Unexpected/TraitFor/ExceptionClasses.pm
Criterion Covered Total %
statement 31 31 100.0
branch 20 20 100.0
condition 7 7 100.0
subroutine 6 6 100.0
pod 3 3 100.0
total 67 67 100.0


line stmt bran cond sub pod time code
1             package Unexpected::TraitFor::ExceptionClasses;
2              
3 2     2   2567 use namespace::autoclean;
  2         4  
  2         9  
4              
5 2     2   97 use Unexpected::Functions qw( inflate_message );
  2         1  
  2         12  
6 2     2   8 use Moo::Role;
  2         3  
  2         9  
7              
8             my $ROOT = 'Unexpected'; my $Classes = { $ROOT => {} };
9              
10             __PACKAGE__->add_exception( 'Unspecified' => {
11             parents => $ROOT, error => 'Parameter [_1] not specified' } );
12              
13             # Public attributes
14             has 'class' => is => 'ro', isa => sub {
15             ($_[ 0 ] and exists $Classes->{ $_[ 0 ] }) or die inflate_message
16             ( 'Exception class [_1] does not exist', $_[ 0 ] ) }, default => $ROOT;
17              
18             # Construction
19             around 'BUILDARGS' => sub {
20             my ($orig, $self, @args) = @_; my $attr = $orig->( $self, @args ); my $class;
21              
22             (exists $attr->{class} and $class = $attr->{class}) or return $attr;
23              
24             ref $class eq 'CODE' and $class = $attr->{class} = $class->();
25              
26             $self->is_exception( $class ) or return $attr;
27              
28             for my $k (grep { ! m{ \A parents \z }mx } keys %{ $Classes->{ $class } }) {
29             $attr->{ $k } //= $Classes->{ $class }->{ $k };
30             }
31              
32             return $attr;
33             };
34              
35             # Public class methods
36             sub add_exception {
37 15   100 15 1 1358 my ($self, $class, $args) = @_; $args //= {};
  15         32  
38              
39 15 100       29 defined $class or die "Parameter 'exception class' not specified";
40              
41 14 100       29 exists $Classes->{ $class }
42             and die "Exception class ${class} already exists";
43              
44 13 100       24 ref $args ne 'HASH' and $args = { parents => $args };
45              
46 13   100     29 my $parents = $args->{parents} //= [ $ROOT ];
47              
48 13 100       28 ref $parents ne 'ARRAY' and $parents = $args->{parents} = [ $parents ];
49              
50 13         9 for my $parent (@{ $parents }) {
  13         16  
51 15 100       71 exists $Classes->{ $parent } or die
52             "Exception class ${class} parent class ${parent} does not exist";
53             }
54              
55 12         20 $Classes->{ $class } = $args;
56 12         16 return;
57             }
58              
59             sub is_exception {
60 22 100 100 22 1 351 return $_[ 1 ] && !ref $_[ 1 ] && exists $Classes->{ $_[ 1 ] } ? 1 : 0;
61             }
62              
63             # Public object methods
64             sub instance_of {
65 10 100   10 1 558 my ($self, $wanted) = @_; $wanted or return 0;
  10         22  
66              
67 9 100       22 exists $Classes->{ $wanted }
68             or die "Exception class ${wanted} does not exist";
69              
70 8         17 my @classes = ( $self->class );
71              
72 8         17 while (defined (my $class = shift @classes)) {
73 20 100       58 $class eq $wanted and return 1;
74             exists $Classes->{ $class }->{parents}
75 14 100       23 and push @classes, @{ $Classes->{ $class }->{parents} };
  11         29  
76             }
77              
78 2         8 return 0;
79             }
80              
81             1;
82              
83             __END__