File Coverage

lib/File/Util/Exception.pm
Criterion Covered Total %
statement 57 72 79.1
branch 15 36 41.6
condition 10 43 23.2
subroutine 9 9 100.0
pod n/a
total 91 160 56.8


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