File Coverage

blib/lib/Error/Pure/Utils.pm
Criterion Covered Total %
statement 84 90 93.3
branch 30 36 83.3
condition 7 18 38.8
subroutine 11 11 100.0
pod 5 5 100.0
total 137 160 85.6


line stmt bran cond sub pod time code
1             package Error::Pure::Utils;
2              
3 28     28   76691 use base qw(Exporter);
  28         1663  
  28         2973  
4 28     28   240 use strict;
  28         55  
  28         653  
5 28     28   134 use warnings;
  28         51  
  28         954  
6              
7 28     28   153 use Cwd qw(abs_path);
  28         51  
  28         1612  
8 28     28   13211 use Readonly;
  28         105774  
  28         32092  
9              
10             our $VERSION = 0.29;
11              
12             Readonly::Array our @EXPORT_OK => qw(clean err_get err_helper err_msg err_msg_hr);
13             Readonly::Scalar my $DOTS => '...';
14             Readonly::Scalar my $EMPTY_STR => q{};
15             Readonly::Scalar my $EVAL => 'eval {...}';
16             Readonly::Scalar my $UNDEF => 'undef';
17              
18             # Errors array.
19             our @ERRORS;
20              
21             # Default initialization.
22             our $LEVEL = 2;
23             our $MAX_LEVELS = 50;
24             our $MAX_EVAL = 100;
25             our $MAX_ARGS = 10;
26             our $MAX_ARG_LEN = 50;
27             our $PROGRAM = $EMPTY_STR; # Program name in stack information.
28              
29             # Clean internal structure.
30             sub clean {
31 11     11 1 7019 @ERRORS = ();
32 11         264 return;
33             }
34              
35             # Get and clean processed errors.
36             sub err_get {
37 10     10 1 1762 my $clean = shift;
38 10         23 my @ret = @ERRORS;
39 10 100       26 if ($clean) {
40 1         5 clean();
41             }
42 10         31 return @ret;
43             }
44              
45             # Process error without die.
46             sub err_helper {
47 55     55 1 437 my @msg = @_;
48              
49             # Check to undefined values in @msg and chomp.
50 55         188 for (my $i = 0; $i < @msg; $i++) {
51 79 100       189 if (! defined $msg[$i]) {
52 7         27 $msg[$i] = $UNDEF;
53             } else {
54 72         201 chomp $msg[$i];
55             }
56             }
57              
58             # When is list blank, add undef.
59 55 100       143 if (! @msg) {
60 6         21 push @msg, $UNDEF;
61             }
62              
63             # Get calling stack.
64 55         129 my @stack = _get_stack();
65              
66             # Create errors message.
67 55         200 push @ERRORS, {
68             'msg' => \@msg,
69             'stack' => \@stack,
70             };
71              
72 55         214 return @ERRORS;
73             }
74              
75             # Get first error messages array.
76             sub err_msg {
77 3     3 1 12 my $index = shift;
78 3 100       8 if (! defined $index) {
79 2         4 $index = -1;
80             }
81 3         6 my @err = err_get();
82 3         4 my @ret = @{$err[$index]->{'msg'}};
  3         10  
83 3         9 return @ret;
84             }
85              
86             # Get first error message key, value pairs as hash reference.
87             sub err_msg_hr {
88 3     3 1 13 my $index = shift;
89 3 100       8 if (! defined $index) {
90 2         3 $index = -1;
91             }
92 3         7 my @err = err_get();
93 3         4 my @ret = @{$err[$index]->{'msg'}};
  3         10  
94 3         4 shift @ret;
95 3         16 return {@ret};
96             }
97              
98             # Get information about place of error.
99             sub _get_stack {
100 55   33 55   222 my $max_level = shift || $MAX_LEVELS;
101 55         94 my @stack;
102 55         122 my $tmp_level = $LEVEL;
103 55         106 my ($class, $prog, $line, $sub, $hargs, $evaltext, $is_require);
104 55   66     150 while ($tmp_level < $max_level
105 143         1087 && do { package DB; ($class, $prog, $line, $sub, $hargs,
106             undef, $evaltext, $is_require) = caller($tmp_level++); }) {
107              
108             # Prog to absolute path.
109 88 100       1455 if (-e $prog) {
110 86         2720 $prog = abs_path($prog);
111             }
112              
113             # Sub name.
114 88 100       342 if (defined $evaltext) {
    100          
115 2 50       6 if ($is_require) {
116 0         0 $sub = "require $evaltext";
117             } else {
118 2         5 $evaltext =~ s/\n;//sm;
119 2         28 $evaltext =~ s/([\'])/\\$1/gsm;
120 2 50 33     13 if ($MAX_EVAL
121             && length($evaltext) > $MAX_EVAL) {
122              
123 2         7 substr($evaltext, $MAX_EVAL, -1,
124             $DOTS);
125             }
126 2         14 $sub = "eval '$evaltext'";
127             }
128              
129             # My eval name.
130             } elsif ($sub eq '(eval)') {
131 41         70 $sub = $EVAL;
132              
133             # Other transformation.
134             } else {
135 45         482 $sub =~ s/^$class\:\:([^:]+)$/$1/gsmx;
136 45 100       310 if ($sub =~ m/^Error::Pure::(.*)err$/smx) {
137 43         82 $sub = 'err';
138             }
139 45 50 33     141 if ($PROGRAM && $prog =~ m/^\(eval/sm) {
140 0         0 $prog = $PROGRAM;
141             }
142             }
143              
144             # Args.
145 88         150 my $i_args = $EMPTY_STR;
146 88 100       168 if ($hargs) {
147 45         118 my @args = @DB::args;
148 45 50 33     220 if ($MAX_ARGS && $#args > $MAX_ARGS) {
149 0         0 $#args = $MAX_ARGS;
150 0         0 $args[-1] = $DOTS;
151             }
152              
153             # Get them all.
154 45         104 foreach my $arg (@args) {
155 41 100       140 if (! defined $arg) {
156 6         18 $arg = 'undef';
157 6         15 next;
158             }
159 35 50       95 if (ref $arg) {
160              
161             # Force string representation.
162 0         0 $arg .= $EMPTY_STR;
163             }
164 35         69 $arg =~ s/'/\\'/gms;
165 35 50 33     142 if ($MAX_ARG_LEN && length $arg> $MAX_ARG_LEN) {
166 0         0 substr $arg, $MAX_ARG_LEN, -1, $DOTS;
167             }
168              
169             # Quote (not for numbers).
170 35 100       140 if ($arg !~ m/^-?[\d.]+$/ms) {
171 33         99 $arg = "'$arg'";
172             }
173             }
174 45         155 $i_args = '('.(join ', ', @args).')';
175             }
176              
177             # Information to stack.
178 88         170 $sub =~ s/\n$//ms;
179 88         470 push @stack, {
180             'class' => $class,
181             'prog' => $prog,
182             'line' => $line,
183             'sub' => $sub,
184             'args' => $i_args
185             };
186             }
187              
188             # Stack.
189 55         164 return @stack;
190             }
191              
192             1;
193              
194             __END__