File Coverage

blib/lib/Exception/FFI/ErrorCode.pm
Criterion Covered Total %
statement 91 101 90.1
branch 15 20 75.0
condition 5 10 50.0
subroutine 18 20 90.0
pod 1 1 100.0
total 130 152 85.5


line stmt bran cond sub pod time code
1             package Exception::FFI::ErrorCode 0.03 {
2              
3 1     1   185784 use warnings;
  1         6  
  1         26  
4 1     1   18 use 5.020;
  1         3  
5 1     1   4 use constant 1.32 ();
  1         10  
  1         17  
6 1     1   435 use experimental qw( signatures postderef );
  1         2830  
  1         4  
7 1     1   636 use Ref::Util qw( is_plain_arrayref );
  1         1370  
  1         185  
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   3978 {
  2         5  
  2         3  
16 2   33     13 my $class = delete $args{class} || caller;
17 2   33     9 my $const_class = delete $args{const_class} || $class;
18 2   100     8 my $codes = delete $args{codes} || {};
19              
20 2 100       4 if(%args) {
21 1         6 require Carp;
22 1         2 Carp::croak("Unknown options: @{[ sort keys %args ]}");
  1         179  
23             }
24              
25             {
26 1     1   6 no strict 'refs';
  1         2  
  1         324  
  1         2  
27 1         2 push @{ "$class\::ISA" }, 'Exception::FFI::ErrorCode::Base';
  1         8  
28             }
29              
30              
31 1         4 foreach my $name (keys $codes->%*)
32             {
33 2         3 my($code, $human) = do {
34 2         3 my $v = $codes->{$name};
35 2 100       7 is_plain_arrayref $v ? @$v : ($v,$name);
36             };
37 2         73 constant->import("$const_class\::$name", $code);
38 2         2346 $human_codes{$class}->{$code} = $human;
39             }
40             }
41              
42             sub detect ($class)
43 1     1 1 2 {
  1         3  
  1         1  
44 1         1 my $sub;
45 1 50       9 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   5 $sub = sub { 0 };
  0         0  
56             }
57 1     1   6 no warnings 'redefine';
  1         2  
  1         100  
58 1         4 *Exception::FFI::ErrorCode::Base::_carp_always = $sub;
59             }
60              
61             __PACKAGE__->detect;
62              
63             package Exception::FFI::ErrorCode::Base 0.03 {
64              
65             sub _carp_always;
66              
67 1     1   411 use Class::Tiny qw( package filename line code trace _longmess );
  1         1529  
  1         4  
68 1     1   764 use Ref::Util qw( is_blessed_ref );
  1         2  
  1         132  
69             use overload
70 1     1   1 '""' => sub ($self,@) {
  1         176  
  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         10  
  4         65  
81              
82 4         9 sub throw ($proto, %rest)
83 4     4   6959 {
  4         8  
  4         4  
84 4   50     36 my($package, $filename, $line) = caller( delete $rest{frame} // 0 );
85              
86 4         9 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         21 $self = $proto->new(
97             %rest,
98             package => $package,
99             filename => $filename,
100             line => $line,
101             );
102             }
103 4         243 my $trace = $self->get_stack_trace;
104 4 100       365 $self->trace($trace) if $trace;
105 4 50       1152 $self->_longmess(Carp::longmess($self->strerror)) if _carp_always;
106 4         30 die $self;
107             }
108              
109             sub get_stack_trace ($)
110 4     4   7 {
  4         6  
111 4 100       8 if($ENV{EXCEPTION_FFI_ERROR_CODE_STACK_TRACE})
112             {
113 1         447 require Devel::StackTrace;
114 1         2754 return Devel::StackTrace->new(
115             ignore_package => 'Exception::FFI::ErrorCode::Base',
116             );
117             }
118             else
119             {
120 3         6 return undef;
121             }
122             }
123              
124             sub strerror ($self)
125 7     7   5273 {
  7         10  
  7         8  
126 7         120 my $code = $self->code;
127 7 50       36 $code = 0 unless defined $code;
128 7         15 my $str = $human_codes{ref $self}->{$code};
129 7 100       48 $str = sprintf "%s error code %s", ref $self, $self->code unless defined $str;
130 7         69 return $str;
131             }
132              
133             sub as_string ($self)
134 4     4   470 {
  4         5  
  4         5  
135 4         9 sprintf "%s at %s line %s.", $self->strerror, $self->filename, $self->line;
136             }
137             }
138             }
139              
140             1;
141              
142             __END__