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   76022 use base qw(Exporter);
  28         86  
  28         2850  
4 28     28   177 use strict;
  28         51  
  28         603  
5 28     28   140 use warnings;
  28         49  
  28         849  
6              
7 28     28   142 use Cwd qw(abs_path);
  28         53  
  28         1581  
8 28     28   12873 use Readonly;
  28         103756  
  28         31287  
9              
10             our $VERSION = 0.31;
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 6612 @ERRORS = ();
32 11         300 return;
33             }
34              
35             # Get and clean processed errors.
36             sub err_get {
37 10     10 1 1344 my $clean = shift;
38 10         21 my @ret = @ERRORS;
39 10 100       29 if ($clean) {
40 1         3 clean();
41             }
42 10         30 return @ret;
43             }
44              
45             # Process error without die.
46             sub err_helper {
47 55     55 1 397 my @msg = @_;
48              
49             # Check to undefined values in @msg and chomp.
50 55         181 for (my $i = 0; $i < @msg; $i++) {
51 79 100       199 if (! defined $msg[$i]) {
52 7         28 $msg[$i] = $UNDEF;
53             } else {
54 72         191 chomp $msg[$i];
55             }
56             }
57              
58             # When is list blank, add undef.
59 55 100       133 if (! @msg) {
60 6         17 push @msg, $UNDEF;
61             }
62              
63             # Get calling stack.
64 55         127 my @stack = _get_stack();
65              
66             # Create errors message.
67 55         194 push @ERRORS, {
68             'msg' => \@msg,
69             'stack' => \@stack,
70             };
71              
72 55         195 return @ERRORS;
73             }
74              
75             # Get first error messages array.
76             sub err_msg {
77 3     3 1 11 my $index = shift;
78 3 100       7 if (! defined $index) {
79 2         4 $index = -1;
80             }
81 3         7 my @err = err_get();
82 3         7 my @ret = @{$err[$index]->{'msg'}};
  3         8  
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 12 my $index = shift;
89 3 100       7 if (! defined $index) {
90 2         4 $index = -1;
91             }
92 3         6 my @err = err_get();
93 3         5 my @ret = @{$err[$index]->{'msg'}};
  3         9  
94 3         4 shift @ret;
95 3         14 return {@ret};
96             }
97              
98             # Get information about place of error.
99             sub _get_stack {
100 55   33 55   233 my $max_level = shift || $MAX_LEVELS;
101 55         98 my @stack;
102 55         131 my $tmp_level = $LEVEL;
103 55         101 my ($class, $prog, $line, $sub, $hargs, $evaltext, $is_require);
104 55   66     135 while ($tmp_level < $max_level
105 143         1027 && 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       1411 if (-e $prog) {
110 86         2958 $prog = abs_path($prog);
111             }
112              
113             # Sub name.
114 88 100       332 if (defined $evaltext) {
    100          
115 2 50       4 if ($is_require) {
116 0         0 $sub = "require $evaltext";
117             } else {
118 2         6 $evaltext =~ s/\n;//sm;
119 2         28 $evaltext =~ s/([\'])/\\$1/gsm;
120 2 50 33     14 if ($MAX_EVAL
121             && length($evaltext) > $MAX_EVAL) {
122              
123 2         13 substr($evaltext, $MAX_EVAL, -1,
124             $DOTS);
125             }
126 2         6 $sub = "eval '$evaltext'";
127             }
128              
129             # My eval name.
130             } elsif ($sub eq '(eval)') {
131 41         71 $sub = $EVAL;
132              
133             # Other transformation.
134             } else {
135 45         452 $sub =~ s/^$class\:\:([^:]+)$/$1/gsmx;
136 45 100       293 if ($sub =~ m/^Error::Pure::(.*)err$/smx) {
137 43         79 $sub = 'err';
138             }
139 45 50 33     135 if ($PROGRAM && $prog =~ m/^\(eval/sm) {
140 0         0 $prog = $PROGRAM;
141             }
142             }
143              
144             # Args.
145 88         137 my $i_args = $EMPTY_STR;
146 88 100       166 if ($hargs) {
147 45         109 my @args = @DB::args;
148 45 50 33     210 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       93 if (! defined $arg) {
156 6         16 $arg = 'undef';
157 6         16 next;
158             }
159 35 50       92 if (ref $arg) {
160              
161             # Force string representation.
162 0         0 $arg .= $EMPTY_STR;
163             }
164 35         106 $arg =~ s/'/\\'/gms;
165 35 50 33     135 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       137 if ($arg !~ m/^-?[\d.]+$/ms) {
171 33         101 $arg = "'$arg'";
172             }
173             }
174 45         153 $i_args = '('.(join ', ', @args).')';
175             }
176              
177             # Information to stack.
178 88         170 $sub =~ s/\n$//ms;
179 88         457 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         169 return @stack;
190             }
191              
192             1;
193              
194             __END__