File Coverage

lib/File/Util/Exception.pm
Criterion Covered Total %
statement 54 69 78.2
branch 15 36 41.6
condition 10 43 23.2
subroutine 8 8 100.0
pod n/a
total 87 156 55.7


line stmt bran cond sub pod time code
1 2     2   451 use strict;
  2         3  
  2         67  
2 2     2   11 use warnings;
  2         2  
  2         101  
3              
4             package File::Util::Exception;
5             $File::Util::Exception::VERSION = '4.201720';
6             # ABSTRACT: Base exception class for File::Util
7              
8 2     2   11 use File::Util::Definitions qw( :all );
  2         4  
  2         477  
9              
10 2         140 use vars qw(
11             @ISA $AUTHORITY
12             @EXPORT_OK %EXPORT_TAGS
13 2     2   13 );
  2         4  
14              
15 2     2   13 use Exporter;
  2         4  
  2         1619  
16              
17             $AUTHORITY = 'cpan:TOMMY';
18             @ISA = qw( Exporter );
19             @EXPORT_OK = qw( _throw );
20             %EXPORT_TAGS = ( all => [ @EXPORT_OK ] );
21              
22              
23             # --------------------------------------------------------
24             # File::Util::Exception::_throw
25             # --------------------------------------------------------
26             sub _throw {
27              
28 1     1   3 my @in = @_;
29 1         3 my ( $this, $error_class, $error ) = splice @_, 0 , 3;
30 1         5 my $opts = $this->_remove_opts( \@_ );
31 1         2 my %fatal_rules = ();
32              
33             # here we handle support for the legacy error handling policy syntax,
34             # such as things like "fatals_as_status => 1"
35             #
36             # ...and we also handle support for the newer, more pretty error
37             # handling policy syntax using "onfail" keywords/subrefs
38              
39             $opts->{onfail} ||=
40             $opts->{opts} && ref $opts->{opts} eq 'HASH'
41             ? $opts->{opts}->{onfail}
42 1 50 33     13 : '';
      33        
43              
44 1   33     2 $opts->{onfail} ||= $this->{opts}->{onfail};
45              
46 1   50     3 $opts->{onfail} ||= 'die';
47              
48             # fatalality-handling rules passed to the failing caller trump the
49             # rules set up in the attributes of the object; the mechanism below
50             # also allows for the implicit handling of fatals_are_fatal => 1
51 1         5 map { $fatal_rules{ $_ } = $_ }
  0         0  
52             grep /^fatals/o, keys %$opts;
53              
54 0         0 map { $fatal_rules{ $_ } = $_ }
55 1         4 grep /^fatals/o, keys %{ $opts->{opts} }
56 1 50 33     6 if $opts->{opts} && ref $opts->{opts} eq 'HASH';
57              
58 1 50       3 unless ( scalar keys %fatal_rules ) {
59 0         0 map { $fatal_rules{ $_ } = $_ }
60 1         3 grep /^fatals/o, keys %{ $this->{opts} }
  1         8  
61             }
62              
63 1 50 33     7 return 0 if $fatal_rules{fatals_as_status} || $opts->{onfail} eq 'zero';
64              
65 1 50       2 return if $opts->{onfail} eq 'undefined';
66              
67 1         2 my $is_plain;
68              
69 1 50       2 if ( !scalar keys %$opts ) {
70              
71 0         0 $opts->{_pak} = 'File::Util';
72              
73 0         0 $opts->{error} = $error;
74              
75 0 0       0 $error = $error ? 'plain error' : 'empty error';
76              
77 0         0 $is_plain++;
78             }
79             else {
80              
81 1         2 $opts->{_pak} = 'File::Util';
82              
83 1   50     2 $error ||= 'empty error';
84              
85 1 50       2 if ( $error eq 'plain error' ) {
86              
87 0   0     0 $opts->{error} ||= shift @_;
88              
89 0         0 $is_plain++;
90             }
91             }
92              
93 1         7 my $bad_news = CORE::eval # tokenizing via stringy eval (is NOT evil)
94             (
95             '<<__ERRBLOCK__' . NL .
96             $error_class->_errors( $error ) . NL .
97             '__ERRBLOCK__'
98             );
99              
100 1 50 33     15 if (
    50 33        
      33        
101             $opts->{onfail} eq 'warn' ||
102             $fatal_rules{fatals_as_warning}
103             ) {
104 0 0 0     0 warn _trace( $@ || $bad_news ) and return;
105             }
106             elsif (
107             $opts->{onfail} eq 'message' ||
108             $fatal_rules{fatals_as_errmsg} ||
109             $opts->{return}
110             ) {
111 0   0     0 return _trace( $@ || $bad_news );
112             }
113              
114 1 50 0     3 warn _trace( $@ || $bad_news ) if $opts->{warn_also};
115              
116             die _trace( $@ || $bad_news )
117 1 50 0     3 unless ref $opts->{onfail} eq 'CODE';
118              
119 1         3 @_ = ( $bad_news, _trace() );
120              
121 1         6 goto $opts->{onfail};
122             }
123              
124              
125              
126             # --------------------------------------------------------
127             # File::Util::Exception::_trace
128             # --------------------------------------------------------
129             sub _trace { # <<<<< this is not a class or object method!
130 1     1   1 my @errors = @_;
131              
132             my
133             (
134 1         2 $pak, $file, $line, $sub,
135             $hasargs, $wantarray, $evaltext, $req_OR_use,
136             @stack, $i, $frame_no
137             );
138              
139 1         2 $frame_no = 0;
140              
141 1         10 while
142             (
143             ( $pak, $file, $line, $sub,
144             $hasargs, $wantarray, $evaltext, $req_OR_use
145             ) = caller( $i++ )
146             )
147             {
148 6         12 $frame_no = $i - 2;
149              
150 6 100       17 next unless $frame_no > 0;
151              
152 4         12 push @stack, <<__ERR__
153             $frame_no. $sub
154             -called at line ($line) of $file
155 4 50       15 @{[ $hasargs
156             ? '-was called with args'
157             : '-was called without args' ]}
158 4 50       26 @{[ $evaltext
159             ? '-was called to evalate text'
160             : '-was not called to evaluate anything' ]}
161             __ERR__
162             }
163              
164 1         2 $i = 0;
165              
166 1         3 for my $error ( @errors ) {
167              
168 0 0       0 $error = '' unless defined $error;
169              
170 0 0       0 if ( !length $error ) {
171              
172 0         0 $error = qq{Something is wrong. Frame no. $frame_no...}
173             }
174              
175 0         0 ++$i;
176             }
177              
178 1         1 chomp for @errors;
179              
180 1         6 return join NL, @errors, @stack;
181             }
182              
183              
184             # --------------------------------------------------------
185             # File::Util::Exception::DESTROY()
186             # --------------------------------------------------------
187       1     sub DESTROY { }
188              
189              
190             1;
191              
192              
193             __END__