File Coverage

blib/lib/Zoidberg/Utils/Error.pm
Criterion Covered Total %
statement 58 75 77.3
branch 20 42 47.6
condition 12 24 50.0
subroutine 11 12 91.6
pod 5 5 100.0
total 106 158 67.0


line stmt bran cond sub pod time code
1              
2             package Zoidberg::Utils::Error;
3              
4             our $VERSION = '0.981';
5              
6 24     24   25617 use strict;
  24         30  
  24         1541  
7 24     24   32881 use Exporter::Tidy default => [qw/error bug todo/];
  24         246  
  24         143  
8             use overload
9             '""' => \&stringify,
10 1     1   9 'eq' => sub { $_[0] },
11 24     24   31883 fallback => 'TRUE';
  24         19234  
  24         234  
12              
13 24     24   1820 use Scalar::Util qw/reftype/;
  24         64  
  24         9116  
14              
15             our $Scope = $0;
16             $Scope =~ s#.*/##;
17              
18             # ################ #
19             # Exported methods #
20             # ################ #
21              
22             sub error {
23 48     48 1 8460 my @caller = caller;
24            
25 48 50 33     227 if ($@ && !@_) { # make it work more like die
26 0         0 my $error = $@;
27 0         0 my $can_propagate = do {
28 0         0 local $@;
29 0         0 eval{ $error->can( 'PROPAGATE') };
  0         0  
30             };
31 0 0       0 die $@->PROPAGATE(@caller[1,2]) if $can_propagate;
32 0         0 unshift @_, PROPAGATE({}, @caller[1,2]), $@;
33             }
34              
35 48         317 my $error = bless {};
36              
37 48         131 for (@_) { # compiling the error here
38 60 100 100     711 if ( (reftype $_ || '') eq 'HASH') { %$error = (%$error, %$_) }
  12         95  
39 48         1188 else { $$error{string} .= $_ }
40             }
41              
42 48 50       430 unless ($$error{string}) {
    50          
43 0 0       0 $$error{string} =
    0          
44             $$error{is_bug} ? 'This is a bug'
45             : $$error{is_todo} ? 'Something TODO here' : 'Error' ;
46             }
47             elsif ($$error{string} =~ s/\(\@INC contains\: (.*?)\)\s*//g) { # make it less verbose
48 0         0 $$error{INC} = $1;
49             }
50              
51             # trace stack
52 48   50     583 $$error{stack} ||= [];
53             {
54 24     24   120 no strict 'refs';
  24         167  
  24         7008  
  48         70  
55 3         26 @caller = caller(${$caller[0].'::ERROR_CALLER'})
  48         724  
56 48 100       73 if ${$caller[0].'::ERROR_CALLER'};
57 48         175 push @{$$error{stack}}, \@caller;
  48         165  
58              
59 48 50 33     120 if ( # debug code
60             $$error{debug} = ${$caller[0].'::DEBUG'}
61             || $Zoidberg::CURRENT->{settings}{debug}
62             ) {
63 0         0 push @{$$error{stack}}, [ (caller $_)[0..2] ]
64 0         0 for (1..$$error{debug});
65             }
66             }
67            
68 48 50       197 if (defined $Scope) { # set fake caller
69 48 50 0     777 $$error{scope} ||= ref($Scope)
      33        
70             ? [ $$Scope[0], $$Scope[1] || $caller[2] ]
71             : [ $Scope ];
72             }
73              
74 48         533 die $error;
75             }
76              
77             sub bug {
78 1     1 1 1562 unshift @_, { is_bug => 1 };
79 1         6 goto \&error;
80             }
81              
82             sub todo {
83 0     0 1 0 unshift @_, { is_todo => 1 };
84 0         0 goto \&error;
85             }
86              
87             # ############## #
88             # Object methods #
89             # ############## #
90              
91             sub stringify {
92             # TODO verbosity optie
93 24     24   205 no warnings; # lots of stupid warnings here (due to 'overload' ?)
  24         40  
  24         8720  
94 127     127 1 519 my $self = shift;
95 127         504 my %opt = @_;
96 127         151 my $string;
97 127 50       326 if ($opt{format} eq 'gnu') {
98 0         0 $string = join( ': ', grep {defined $_}
  0         0  
99 0 0       0 ( $$self{scope} ? (@{$$self{scope}}) : (@{$$self{stack}[0]}) ),
  0 0       0  
    0          
100             ( $$self{is_bug} ? 'BUG' : $$self{is_todo} ? 'TODO' : undef ),
101             $$self{string} ) . "\n" ;
102             }
103             else {
104 127 50       579 $string = ($$self{is_bug} ? 'BUG: ' : $$self{is_todo} ? 'TODO: ' : '')
    50          
105             . $self->{string};
106 127 50       969 $string .= qq# at $$self{stack}[0][1] line $$self{stack}[0][2]\n#
107             unless $string =~ /\n$/;
108 127 100 66     826 if (exists $$self{propagated} and ref $$self{propagated}) {
109 104         118 $string = PROPAGATE($string, @$_) for @{$self->{propagated}};
  104         428  
110             }
111             }
112 127         3369 return $string;
113             }
114              
115             sub PROPAGATE { # see perldoc -f die
116 178     178 1 374 my ($self, $file, $line) = @_;
117 178 100 66     524 ($file, $line) = ( caller() )[1,2] unless $file or $line;
118 178 100       312 if (ref $self) {
119 20   100     352 $self->{propagated} ||= [];
120 20         36 push @{$self->{propagated}}, [$file, $line];
  20         72  
121             }
122 158         380 else { $self .= "\t...propagated at $file line $line\n" }
123 178         668 return $self;
124             }
125              
126              
127             1;
128              
129             __END__