File Coverage

blib/lib/Exception/FFI/ErrorCode.pm
Criterion Covered Total %
statement 91 101 90.1
branch 15 20 75.0
condition 4 8 50.0
subroutine 18 20 90.0
pod 1 1 100.0
total 129 150 86.0


line stmt bran cond sub pod time code
1             package Exception::FFI::ErrorCode 0.02 {
2              
3 1     1   189920 use warnings;
  1         7  
  1         25  
4 1     1   18 use 5.020;
  1         3  
5 1     1   4 use constant 1.32 ();
  1         12  
  1         18  
6 1     1   420 use experimental qw( signatures postderef );
  1         2942  
  1         5  
7 1     1   618 use Ref::Util qw( is_plain_arrayref );
  1         1396  
  1         180  
8              
9             # ABSTRACT: Exception class based on integer error codes common in C code
10              
11              
12             my %human_codes;
13              
14             sub import ($, %args)
15 2     2   4151 {
  2         6  
  2         3  
16 2   33     15 my $class = delete $args{class} || caller;
17 2   33     9 my $const_class = delete $args{const_class} || $class;
18 2   100     9 my $codes = delete $args{codes} || {};
19              
20 2 100       6 if(%args) {
21 1         7 require Carp;
22 1         3 Carp::croak("Unknown options: @{[ sort keys %args ]}");
  1         211  
23             }
24              
25             {
26 1     1   6 no strict 'refs';
  1         2  
  1         333  
  1         2  
27 1         1 push @{ "$class\::ISA" }, 'Exception::FFI::ErrorCode::Base';
  1         9  
28             }
29              
30              
31 1         3 foreach my $name (keys $codes->%*)
32             {
33 2         3 my($code, $human) = do {
34 2         4 my $v = $codes->{$name};
35 2 100       7 is_plain_arrayref $v ? @$v : ($v,$name);
36             };
37 2         77 constant->import("$const_class\::$name", $code);
38 2         2533 $human_codes{$class}->{$code} = $human;
39             }
40             }
41              
42             sub detect ($class)
43 1     1 1 2 {
  1         3  
  1         2  
44 1         1 my $sub;
45 1 50       10 if(Carp::Always->can('import'))
46             {
47 0         0 require Sub::Identify;
48 0         0 $Carp::CarpInternal{"Exception::FFI::ErrorCode::Base"}++;
49             $sub = sub {
50 0     0   0 [Sub::Identify::get_code_info($SIG{__WARN__})]->[0] eq 'Carp::Always'
51 0         0 };
52             }
53             else
54             {
55 1     0   4 $sub = sub { 0 };
  0         0  
56             }
57 1     1   7 no warnings 'redefine';
  1         2  
  1         103  
58 1         4 *Exception::FFI::ErrorCode::Base::_carp_always = $sub;
59             }
60              
61             __PACKAGE__->detect;
62              
63             package Exception::FFI::ErrorCode::Base 0.02 {
64              
65             sub _carp_always;
66              
67 1     1   411 use Class::Tiny qw( package filename line code trace _longmess );
  1         1529  
  1         3  
68 1     1   782 use Ref::Util qw( is_blessed_ref );
  1         2  
  1         134  
69             use overload
70 1     1   1 '""' => sub ($self,@) {
  1         178  
  1         2  
71 1 50       3 if(_carp_always)
72             {
73 0         0 return $self->_longmess;
74             }
75             else
76             {
77 1         6 return $self->as_string . "\n";
78             }
79             },
80 1     1   6 bool => sub { 1 }, fallback => 1;
  1     4   2  
  1         9  
  4         75  
81              
82 4         5 sub throw ($proto, @rest)
83 4     4   7274 {
  4         9  
  4         5  
84 4         11 my($package, $filename, $line) = caller;
85              
86 4         7 my $self;
87 4 50       10 if(is_blessed_ref $proto)
88             {
89 0         0 $self = $proto;
90 0         0 $self->package($package);
91 0         0 $self->filename($filename);
92 0         0 $self->line($line);
93             }
94             else
95             {
96 4         19 $self = $proto->new(
97             @rest,
98             package => $package,
99             filename => $filename,
100             line => $line,
101             );
102             }
103 4         254 my $trace = $self->get_stack_trace;
104 4 100       366 $self->trace($trace) if $trace;
105 4 50       1125 $self->_longmess(Carp::longmess($self->strerror)) if _carp_always;
106 4         33 die $self;
107             }
108              
109             sub get_stack_trace ($)
110 4     4   7 {
  4         5  
111 4 100       10 if($ENV{EXCEPTION_FFI_ERROR_CODE_STACK_TRACE})
112             {
113 1         499 require Devel::StackTrace;
114 1         2865 return Devel::StackTrace->new(
115             ignore_package => 'Exception::FFI::ErrorCode::Base',
116             );
117             }
118             else
119             {
120 3         5 return undef;
121             }
122             }
123              
124             sub strerror ($self)
125 7     7   5384 {
  7         9  
  7         9  
126 7         130 my $code = $self->code;
127 7 50       39 $code = 0 unless defined $code;
128 7         16 my $str = $human_codes{ref $self}->{$code};
129 7 100       44 $str = sprintf "%s error code %s", ref $self, $self->code unless defined $str;
130 7         71 return $str;
131             }
132              
133             sub as_string ($self)
134 4     4   472 {
  4         8  
  4         5  
135 4         7 sprintf "%s at %s line %s.", $self->strerror, $self->filename, $self->line;
136             }
137             }
138             }
139              
140             1;
141              
142             __END__