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   76620 use base qw(Exporter);
  28         113  
  28         4674  
4 28     28   183 use strict;
  28         66  
  28         622  
5 28     28   142 use warnings;
  28         63  
  28         922  
6              
7 28     28   156 use Cwd qw(abs_path);
  28         71  
  28         1620  
8 28     28   14089 use Readonly;
  28         110129  
  28         33149  
9              
10             our $VERSION = 0.30;
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 8235 @ERRORS = ();
32 11         293 return;
33             }
34              
35             # Get and clean processed errors.
36             sub err_get {
37 10     10 1 1520 my $clean = shift;
38 10         21 my @ret = @ERRORS;
39 10 100       28 if ($clean) {
40 1         4 clean();
41             }
42 10         32 return @ret;
43             }
44              
45             # Process error without die.
46             sub err_helper {
47 55     55 1 420 my @msg = @_;
48              
49             # Check to undefined values in @msg and chomp.
50 55         191 for (my $i = 0; $i < @msg; $i++) {
51 79 100       181 if (! defined $msg[$i]) {
52 7         55 $msg[$i] = $UNDEF;
53             } else {
54 72         198 chomp $msg[$i];
55             }
56             }
57              
58             # When is list blank, add undef.
59 55 100       151 if (! @msg) {
60 6         19 push @msg, $UNDEF;
61             }
62              
63             # Get calling stack.
64 55         124 my @stack = _get_stack();
65              
66             # Create errors message.
67 55         206 push @ERRORS, {
68             'msg' => \@msg,
69             'stack' => \@stack,
70             };
71              
72 55         240 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       8 if (! defined $index) {
79 2         4 $index = -1;
80             }
81 3         5 my @err = err_get();
82 3         5 my @ret = @{$err[$index]->{'msg'}};
  3         9  
83 3         11 return @ret;
84             }
85              
86             # Get first error message key, value pairs as hash reference.
87             sub err_msg_hr {
88 3     3 1 11 my $index = shift;
89 3 100       9 if (! defined $index) {
90 2         3 $index = -1;
91             }
92 3         6 my @err = err_get();
93 3         6 my @ret = @{$err[$index]->{'msg'}};
  3         8  
94 3         6 shift @ret;
95 3         24 return {@ret};
96             }
97              
98             # Get information about place of error.
99             sub _get_stack {
100 55   33 55   223 my $max_level = shift || $MAX_LEVELS;
101 55         105 my @stack;
102 55         149 my $tmp_level = $LEVEL;
103 55         152 my ($class, $prog, $line, $sub, $hargs, $evaltext, $is_require);
104 55   66     139 while ($tmp_level < $max_level
105 143         1047 && 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       1438 if (-e $prog) {
110 86         2747 $prog = abs_path($prog);
111             }
112              
113             # Sub name.
114 88 100       364 if (defined $evaltext) {
    100          
115 2 50       5 if ($is_require) {
116 0         0 $sub = "require $evaltext";
117             } else {
118 2         7 $evaltext =~ s/\n;//sm;
119 2         28 $evaltext =~ s/([\'])/\\$1/gsm;
120 2 50 33     12 if ($MAX_EVAL
121             && length($evaltext) > $MAX_EVAL) {
122              
123 2         6 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         74 $sub = $EVAL;
132              
133             # Other transformation.
134             } else {
135 45         480 $sub =~ s/^$class\:\:([^:]+)$/$1/gsmx;
136 45 100       316 if ($sub =~ m/^Error::Pure::(.*)err$/smx) {
137 43         84 $sub = 'err';
138             }
139 45 50 33     175 if ($PROGRAM && $prog =~ m/^\(eval/sm) {
140 0         0 $prog = $PROGRAM;
141             }
142             }
143              
144             # Args.
145 88         144 my $i_args = $EMPTY_STR;
146 88 100       178 if ($hargs) {
147 45         123 my @args = @DB::args;
148 45 50 33     204 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         101 foreach my $arg (@args) {
155 41 100       100 if (! defined $arg) {
156 6         16 $arg = 'undef';
157 6         17 next;
158             }
159 35 50       93 if (ref $arg) {
160              
161             # Force string representation.
162 0         0 $arg .= $EMPTY_STR;
163             }
164 35         70 $arg =~ s/'/\\'/gms;
165 35 50 33     127 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       139 if ($arg !~ m/^-?[\d.]+$/ms) {
171 33         111 $arg = "'$arg'";
172             }
173             }
174 45         154 $i_args = '('.(join ', ', @args).')';
175             }
176              
177             # Information to stack.
178 88         159 $sub =~ s/\n$//ms;
179 88         469 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         168 return @stack;
190             }
191              
192             1;
193              
194             __END__