File Coverage

blib/lib/Parse/ErrorString/Perl.pm
Criterion Covered Total %
statement 1123 1166 96.3
branch 1012 1968 51.4
condition 14 21 66.6
subroutine 21 21 100.0
pod 2 3 66.6
total 2172 3179 68.3


line stmt bran cond sub pod time code
1             package Parse::ErrorString::Perl;
2              
3 6     6   168595 use v5.8.7;
  6         21  
  6         290  
4 6     6   31 use strict;
  6         12  
  6         222  
5 6     6   29 use warnings;
  6         13  
  6         301  
6              
7             our $VERSION = '0.21';
8              
9 6     6   30 use Carp qw(carp cluck);
  6         17  
  6         532  
10 6     6   32 use Pod::Find ();
  6         8  
  6         123  
11 6     6   6532 use Pod::POM 0.27 ();
  6         255037  
  6         170  
12 6     6   119 use File::Spec ();
  6         14  
  6         95  
13 6     6   36 use File::Basename ();
  6         15  
  6         94  
14 6     6   4480 use Parse::ErrorString::Perl::ErrorItem ();
  6         21  
  6         124  
15 6     6   3924 use Parse::ErrorString::Perl::StackItem ();
  6         14  
  6         888  
16              
17             sub new {
18 6     6 1 105 my $class = shift;
19 6         162 my %options = @_;
20 6   33     59 my $self = bless {}, ref $class || $class;
21 6         33 $self->_prepare_diagnostics;
22 6         280 $self->_prepare_localized_diagnostics(%options);
23 6         71 my %error_desc_hash = (
24             W => 'warning',
25             D => 'deprecation',
26             S => 'severe warning',
27             F => 'fatal error',
28             P => 'internal error',
29             X => 'very fatal error',
30             A => 'alien error message',
31             );
32 6         27 $self->{error_desc_hash} = \%error_desc_hash;
33 6         51 return $self;
34             }
35              
36             sub parse_string {
37 15     15 1 27197 my $self = shift;
38 15         34 my $string = shift;
39              
40             # installs a sub named 'transmo', which returns the type of the error message
41 15 100       71 if ( $self->{transmo} ) {
42 6     6   32 no warnings 'redefine';
  6         37  
  6         16828  
43 6 50   28 0 140584 eval $self->{transmo};
  28 50       58  
  28 50       87  
  28 50       84  
  28 50       73  
  28 50       69  
  28 50       77  
  28 50       66  
  28 50       60  
  28 50       70  
  28 50       66  
  28 50       62  
  28 50       65  
  28 50       65  
  28 50       64  
  28 50       75  
  28 50       66  
  28 50       64  
  28 50       62  
  28 50       64  
  28 50       70  
  28 50       62  
  28 50       69  
  28 50       69  
  28 50       61  
  28 50       64  
  28 50       67  
  28 50       66  
  28 50       60  
  28 50       64  
  28 50       61  
  28 50       100  
  28 50       59  
  28 50       67  
  28 50       67  
  28 50       98  
  28 50       218  
  28 50       67  
  28 50       74  
  28 50       98  
  28 50       64  
  28 50       67  
  28 50       60  
  28 50       104  
  28 50       76  
  28 50       57  
  28 50       62  
  28 50       98  
  28 50       64  
  28 50       69  
  28 50       56  
  28 50       67  
  28 50       69  
  28 50       61  
  28 50       64  
  28 50       97  
  28 50       66  
  28 50       65  
  28 50       63  
  28 50       73  
  28 50       62  
  28 50       62  
  28 50       57  
  28 50       68  
  28 50       61  
  28 50       63  
  28 50       59  
  28 50       62  
  28 50       63  
  28 50       59  
  28 50       68  
  28 50       146  
  28 50       64  
  28 50       58  
  28 50       66  
  28 50       64  
  28 50       57  
  28 50       74  
  28 50       61  
  28 50       64  
  28 50       63  
  28 50       67  
  28 50       61  
  28 50       62  
  28 50       64  
  28 50       60  
  28 50       61  
  28 50       58  
  28 50       83  
  28 50       57  
  28 50       54  
  28 50       67  
  28 50       60  
  28 50       56  
  28 50       63  
  28 50       58  
  28 50       61  
  28 50       64  
  28 50       55  
  28 50       70  
  28 50       71  
  28 50       69  
  28 50       65  
  28 50       65  
  28 50       65  
  28 50       67  
  28 50       64  
  28 50       62  
  28 50       59  
  28 50       64  
  28 50       60  
  28 50       54  
  28 50       70  
  28 50       61  
  28 50       70  
  28 50       62  
  28 50       58  
  28 50       61  
  28 50       61  
  28 50       63  
  28 50       61  
  28 50       57  
  28 50       62  
  28 50       61  
  28 50       61  
  28 50       61  
  28 50       63  
  28 50       60  
  28 50       65  
  28 50       63  
  28 50       60  
  28 50       57  
  28 50       62  
  28 50       64  
  28 50       59  
  28 50       65  
  28 50       57  
  28 50       61  
  28 50       67  
  28 50       59  
  28 50       57  
  28 50       60  
  28 50       61  
  28 50       58  
  28 50       56  
  28 50       60  
  28 50       67  
  28 50       61  
  28 50       63  
  28 50       64  
  28 50       60  
  28 50       60  
  28 50       60  
  28 50       62  
  28 50       61  
  28 50       62  
  28 50       62  
  28 50       57  
  28 50       60  
  28 50       62  
  28 50       59  
  28 50       58  
  28 50       60  
  28 50       61  
  28 50       68  
  28 50       60  
  28 50       65  
  28 50       57  
  28 50       67  
  28 50       62  
  28 50       50  
  28 50       62  
  28 50       53  
  28 50       62  
  28 50       56  
  28 50       56  
  28 50       60  
  28 50       55  
  28 50       56  
  28 50       68  
  28 50       73  
  28 50       63  
  28 50       65  
  28 50       55  
  28 50       61  
  28 50       67  
  28 50       56  
  28 50       62  
  28 50       58  
  28 50       52  
  28 50       66  
  28 50       62  
  28 50       60  
  28 50       54  
  28 50       72  
  28 50       59  
  28 50       58  
  28 50       61  
  28 100       58  
  28 50       54  
  28 50       83  
  24 100       56  
  24 50       52  
  24 100       64  
  23 50       46  
  23 50       66  
  21 50       47  
  21 50       47  
  21 50       45  
  21 50       51  
  21 50       39  
  21 50       45  
  21 50       39  
  21 50       45  
  21 50       39  
  21 50       53  
  21 50       44  
  21 50       42  
  21 50       50  
  21 50       42  
  21 50       48  
  21 50       41  
  21 50       48  
  21 50       59  
  21 50       47  
  21 50       39  
  21 50       49  
  21 50       58  
  21 50       46  
  21 50       61  
  21 50       54  
  21 50       46  
  21 50       41  
  21 50       44  
  21 50       43  
  21 50       40  
  21 50       43  
  21 50       47  
  21 50       46  
  21 50       42  
  21 50       41  
  21 50       42  
  21 50       46  
  21 50       48  
  21 50       42  
  21 50       49  
  21 50       43  
  21 50       45  
  21 50       41  
  21 50       47  
  21 50       43  
  21 50       92  
  21 50       48  
  21 50       45  
  21 50       47  
  21 50       42  
  21 50       42  
  21 50       82  
  21 50       42  
  21 50       43  
  21 50       45  
  21 50       44  
  21 50       43  
  21 50       43  
  21 50       44  
  21 50       42  
  21 50       38  
  21 50       45  
  21 50       39  
  21 50       44  
  21 50       43  
  21 50       37  
  21 50       89  
  21 50       42  
  21 50       43  
  21 50       44  
  21 50       42  
  21 50       43  
  21 50       38  
  21 50       45  
  21 50       41  
  21 50       46  
  21 50       45  
  21 50       35  
  21 50       43  
  21 50       38  
  21 50       42  
  21 50       86  
  21 50       48  
  21 50       41  
  21 50       53  
  21 50       43  
  21 50       43  
  21 50       41  
  21 50       41  
  21 50       85  
  21 50       37  
  21 50       42  
  21 50       42  
  21 50       43  
  21 50       43  
  21 50       39  
  21 50       40  
  21 50       93  
  21 50       58  
  21 50       45  
  21 50       112  
  21 50       44  
  21 50       37  
  21 50       44  
  21 50       42  
  21 50       43  
  21 50       40  
  21 50       43  
  21 50       47  
  21 50       35  
  21 50       46  
  21 50       42  
  21 50       41  
  21 50       43  
  21 50       42  
  21 50       42  
  21 50       37  
  21 50       46  
  21 50       44  
  21 50       39  
  21 50       41  
  21 50       41  
  21 50       43  
  21 50       39  
  21 50       44  
  21 50       43  
  21 50       41  
  21 50       46  
  21 50       42  
  21 50       44  
  21 50       39  
  21 50       47  
  21 50       112  
  21 50       44  
  21 50       42  
  21 50       45  
  21 50       44  
  21 50       44  
  21 50       42  
  21 50       40  
  21 50       44  
  21 50       43  
  21 50       45  
  21 50       43  
  21 50       43  
  21 50       44  
  21 50       45  
  21 50       48  
  21 50       41  
  21 50       42  
  21 50       45  
  21 50       41  
  21 50       41  
  21 50       45  
  21 50       40  
  21 50       45  
  21 50       39  
  21 50       44  
  21 50       44  
  21 50       45  
  21 50       40  
  21 50       41  
  21 50       42  
  21 50       38  
  21 50       39  
  21 50       44  
  21 50       44  
  21 50       43  
  21 50       46  
  21 50       44  
  21 50       38  
  21 50       39  
  21 50       41  
  21 50       44  
  21 50       40  
  21 50       96  
  21 50       49  
  21 50       43  
  21 50       42  
  21 50       43  
  21 50       39  
  21 50       46  
  21 50       40  
  21 50       48  
  21 50       65  
  21 50       43  
  21 50       48  
  21 50       39  
  21 50       43  
  21 50       129  
  21 50       45  
  21 50       42  
  21 50       48  
  21 50       44  
  21 50       40  
  21 50       42  
  21 50       40  
  21 50       44  
  21 50       50  
  21 50       60  
  21 50       44  
  21 50       45  
  21 50       44  
  21 50       43  
  21 50       44  
  21 50       60  
  21 50       38  
  21 50       42  
  21 50       43  
  21 50       42  
  21 50       43  
  21 50       44  
  21 50       43  
  21 50       35  
  21 50       45  
  21 50       44  
  21 50       39  
  21 50       44  
  21 50       42  
  21 50       43  
  21 50       47  
  21 50       67  
  21 50       66  
  21 50       41  
  21 50       42  
  21 50       46  
  21 50       42  
  21 50       57  
  21 50       43  
  21 50       42  
  21 50       44  
  21 50       42  
  21 50       40  
  21 50       40  
  21 50       45  
  21 50       53  
  21 50       39  
  21 50       46  
  21 50       38  
  21 50       52  
  21 50       38  
  21 50       52  
  21 50       43  
  21 50       41  
  21 50       46  
  21 50       38  
  21 50       41  
  21 50       45  
  21 50       42  
  21 50       40  
  21 50       41  
  21 50       44  
  21 50       43  
  21 50       63  
  21 50       42  
  21 50       43  
  21 50       43  
  21 50       42  
  21 50       38  
  21 50       41  
  21 50       40  
  21 50       40  
  21 50       45  
  21 50       37  
  21 50       45  
  21 50       63  
  21 50       46  
  21 50       41  
  21 50       49  
  21 50       41  
  21 100       44  
  21 50       37  
  21 100       52  
  19 50       61  
  19 50       40  
  18 50       35  
  18 50       37  
  18 50       54  
  18 50       41  
  18 50       57  
  18 50       67  
  18 50       37  
  18 50       37  
  18 50       39  
  18 50       36  
  18 50       38  
  18 50       35  
  18 50       37  
  18 50       34  
  18 50       39  
  18 50       86  
  18 50       35  
  18 50       38  
  18 50       36  
  18 50       43  
  18 50       35  
  18 50       40  
  18 50       39  
  18 50       37  
  18 50       36  
  18 50       37  
  18 50       36  
  18 50       37  
  18 50       36  
  18 50       37  
  18 50       42  
  18 50       41  
  18 50       37  
  18 50       33  
  18 50       39  
  18 50       38  
  18 50       37  
  18 50       32  
  18 50       152  
  18 50       36  
  18 50       39  
  18 50       33  
  18 50       39  
  18 50       96  
  18 50       249  
  18 50       35  
  18 50       41  
  18 50       37  
  18 50       37  
  18 50       35  
  18 50       286  
  18 50       43  
  18 50       39  
  18 50       32  
  18 50       188  
  18 50       36  
  18 50       39  
  18 50       196  
  18 50       32  
  18 50       40  
  18 50       38  
  18 50       38  
  18 50       188  
  18 50       37  
  18 50       36  
  18 50       37  
  18 50       33  
  18 50       38  
  18 50       36  
  18 50       39  
  18 50       196  
  18 50       41  
  18 50       70  
  18 50       39  
  18 50       39  
  18 50       33  
  18 50       38  
  18 50       42  
  18 50       38  
  18 50       41  
  18 50       200  
  18 50       36  
  18 50       40  
  18 50       37  
  18 50       196  
  18 50       39  
  18 50       39  
  18 50       35  
  18 50       31  
  18 50       228  
  18 50       42  
  18 50       37  
  18 50       32  
  18 50       36  
  18 50       34  
  18 50       38  
  18 50       205  
  18 50       36  
  18 50       37  
  18 50       37  
  18 50       33  
  18 50       31  
  18 50       37  
  18 50       37  
  18 50       37  
  18 50       202  
  18 50       37  
  18 50       131  
  18 50       40  
  18 50       37  
  18 50       38  
  18 50       206  
  18 50       39  
  18 50       35  
  18 50       37  
  18 50       39  
  18 50       201  
  18 50       35  
  18 50       39  
  18 50       38  
  18 50       43  
  18 50       200  
  18 50       39  
  18 50       33  
  18 50       206  
  18 50       39  
  18 50       151  
  18 50       42  
  18 50       37  
  18 50       40  
  18 50       70  
  18 50       37  
  18 50       229  
  18 50       37  
  18 50       114  
  18 50       37  
  18 50       38  
  18 50       37  
  18 50       39  
  18 50       38  
  18 50       207  
  18 50       36  
  18 50       36  
  18 50       38  
  18 50       205  
  18 50       41  
  18 50       39  
  18 50       40  
  18 50       216  
  18 50       203  
  18 50       44  
  18 50       37  
  18 50       35  
  18 50       41  
  18 50       38  
  18 50       43  
  18 50       205  
  18 50       40  
  18 50       37  
  18 50       204  
  18 50       41  
  18 50       39  
  18 50       37  
  18 50       581  
  18 50       39  
  18 50       36  
  18 50       42  
  18 50       35  
  18 50       41  
  18 50       37  
  18 50       38  
  18 50       227  
  18 50       45  
  18 50       36  
  18 50       35  
  18 50       39  
  18 50       37  
  18 100       230  
  18 50       37  
  18 50       47  
  17 50       41  
  17 50       37  
  17 50       36  
  17 50       38  
  17 50       208  
  17 50       62  
  17 50       36  
  17 50       41  
  17 50       39  
  17 100       33  
  17 50       39  
  17 100       66  
  15 100       30  
  15 50       266  
  13 50       37  
  12 50       28  
  12 50       26  
  12 50       26  
  12 50       27  
  12 50       197  
  12 50       26  
  12 50       27  
  12 50       28  
  12 50       27  
  12 50       208  
  12 50       24  
  12 50       29  
  12 50       24  
  12 50       27  
  12 50       25  
  12 50       22  
  12 50       26  
  12 50       221  
  12 50       27  
  12 50       24  
  12 50       22  
  12 50       26  
  12 50       25  
  12 50       22  
  12 50       24  
  12 50       25  
  12 50       217  
  12 50       24  
  12 50       25  
  12 50       24  
  12 50       26  
  12 50       22  
  12 50       27  
  12 50       28  
  12 50       25  
  12 50       29  
  12 50       25  
  12 50       24  
  12 50       24  
  12 50       25  
  12 50       25  
  12 50       26  
  12 50       26  
  12 50       26  
  12 50       23  
  12 50       22  
  12 50       25  
  12 50       24  
  12 50       25  
  12 50       24  
  12 50       25  
  12 50       24  
  12 50       28  
  12 50       24  
  12 50       24  
  12 50       26  
  12 50       52  
  12 50       23  
  12 50       27  
  12 50       24  
  12 50       29  
  12 50       30  
  12 50       24  
  12 50       26  
  12 50       27  
  12 50       25  
  12 50       27  
  12 50       24  
  12 50       26  
  12 50       26  
  12 50       25  
  12 50       23  
  12 50       24  
  12 50       26  
  12 50       22  
  12 50       23  
  12 50       25  
  12 50       29  
  12 50       26  
  12 50       31  
  12 50       23  
  12 50       25  
  12 50       26  
  12 50       25  
  12 50       27  
  12 50       28  
  12 50       27  
  12 50       121  
  12 50       25  
  12 50       49  
  12 50       25  
  12 50       25  
  12 50       28  
  12 50       24  
  12 100       106  
  12 50       27  
  12 50       32  
  11 50       26  
  11 50       26  
  11 50       27  
  11 100       26  
  11 50       30  
  11 50       29  
  10 50       24  
  10 50       24  
  10 50       21  
  10 50       20  
  10 100       121  
  10 50       23  
  10 50       29  
  9 50       21  
  9 50       19  
  9 50       18  
  9 50       18  
  9 100       17  
  9 50       21  
  9 50       30  
  7 50       17  
  7 50       18  
  7 50       14  
  7 50       13  
  7 50       16  
  7 50       13  
  7 50       15  
  7 50       16  
  7 50       13  
  7 50       17  
  7 50       13  
  7 50       13  
  7 50       13  
  7 50       14  
  7 50       15  
  7 50       17  
  7 50       13  
  7 50       15  
  7 50       13  
  7 50       15  
  7 50       14  
  7 50       15  
  7 50       14  
  7 50       13  
  7 50       15  
  7 50       14  
  7 50       12  
  7 50       15  
  7 50       16  
  7 50       16  
  7 50       14  
  7 50       15  
  7 50       16  
  7 50       15  
  7 50       15  
  7 50       10  
  7 50       16  
  7 50       14  
  7 50       15  
  7 50       17  
  7 50       11  
  7 50       13  
  7 50       18  
  7 50       16  
  7 50       16  
  7 50       15  
  7 50       14  
  7 50       14  
  7 50       14  
  7 50       20  
  7 50       15  
  7 50       19  
  7 50       17  
  7 50       17  
  7 50       15  
  7 50       17  
  7 50       16  
  7 50       18  
  7 50       13  
  7 50       17  
  7 50       17  
  7 50       13  
  7 50       16  
  7 50       14  
  7 50       13  
  7 50       15  
  7 50       14  
  7 50       16  
  7 50       14  
  7 50       13  
  7 50       16  
  7 50       15  
  7 50       14  
  7 50       13  
  7 50       14  
  7 50       15  
  7 50       13  
  7 50       17  
  7 50       13  
  7 50       16  
  7 50       18  
  7 50       13  
  7 50       16  
  7 50       16  
  7 50       15  
  7 50       15  
  7 50       18  
  7 50       17  
  7 50       14  
  7 50       14  
  7 50       17  
  7 50       15  
  7 50       13  
  7 50       16  
  7 50       79  
  7 50       17  
  7 50       18  
  7 50       14  
  7 50       15  
  7 50       17  
  7 50       14  
  7 50       17  
  7 50       17  
  7 50       14  
  7 50       16  
  7 50       14  
  7 50       17  
  7 50       15  
  7 50       14  
  7 50       16  
  7 50       18  
  7 50       15  
  7 50       17  
  7 50       14  
  7 50       13  
  7 50       15  
  7 50       19  
  7 50       17  
  7 50       12  
  7 50       17  
  7 50       11  
  7 50       16  
  7 50       13  
  7 50       14  
  7 50       18  
  7 50       18  
  7 50       14  
  7 50       15  
  7 50       16  
  7 50       18  
  7 50       15  
  7 50       17  
  7 50       12  
  7 50       15  
  7 100       15  
  7 50       19  
  7 50       38  
  4 50       10  
  4 50       9  
  4 50       9  
  4 0       11  
  4 0       32  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
44 6 50       2162 carp $@ if $@;
45 6         89 $self->{transmo} = undef;
46             }
47              
48 15         88 my @hash_items = $self->_parse_to_hash($string);
49 15         23 my @object_items;
50              
51 15         33 foreach my $item (@hash_items) {
52 22         157 my $error_object = Parse::ErrorString::Perl::ErrorItem->new($item);
53 22         56 push @object_items, $error_object;
54             }
55              
56 15         72 return @object_items;
57             }
58              
59             sub _prepare_diagnostics {
60 6     6   14 my $self = shift;
61 6         12 my %options = @_;
62              
63 6         12 my $perldiag;
64             my $pod_filename;
65              
66 6 50       24 if ( $options{lang} ) {
67 0         0 $perldiag = 'POD2::' . $options{lang} . '::perldiag';
68 0         0 $pod_filename = Pod::Find::pod_where( { -inc => 1 }, $perldiag );
69              
70 0 0       0 if ( !$pod_filename ) {
71 0         0 carp "Could not locate localised perldiag, trying perldiag in English";
72             }
73             }
74              
75 6 50       29 if ( !$pod_filename ) {
76 6         15705 $pod_filename = Pod::Find::pod_where( { -inc => 1 }, 'perldiag' );
77              
78 6 50       57 if ( !$pod_filename ) {
79 0         0 carp "Could not locate perldiag, diagnostic info will no be added";
80 0         0 return;
81             }
82             }
83              
84              
85 6         85 my $parser = Pod::POM->new();
86 6         159 my $pom = $parser->parse_file($pod_filename);
87 6 50       3164531 if ( !$pom ) {
88 0         0 carp $parser->error();
89 0         0 return;
90             }
91              
92 6         175 my %transfmt = ();
93 6         22 my %errors;
94 6         181 foreach my $item ( $pom->head1->[1]->over->[0]->item ) {
95 5622         356017 my $header = $item->title;
96              
97 5622         95318 my $content = $item->content;
98 5622         89461 $content =~ s/\s*$//;
99 5622         2053042 $errors{$header} = $content;
100              
101              
102             ### CODE FROM SPLAIN
103              
104             #$header =~ s/[A-Z]<(.*?)>/$1/g;
105              
106 5622         270054 my @toks = split( /(%l?[dx]|%c|%(?:\.\d+)?s)/, $header );
107 5622 100       275215 if ( @toks > 1 ) {
108 3186         4421 my $conlen = 0;
109 3186         7935 for my $i ( 0 .. $#toks ) {
110 10842 100       27067 if ( $i % 2 ) {
    100          
111 4338 100       12852 if ( $toks[$i] eq '%c' ) {
    100          
    100          
    50          
    100          
112 336         2747 $toks[$i] = '.';
113             } elsif ( $toks[$i] eq '%d' ) {
114 294         671 $toks[$i] = '\d+';
115             } elsif ( $toks[$i] eq '%s' ) {
116 3642 100       10698 $toks[$i] = $i == $#toks ? '.*' : '.*?';
117             } elsif ( $toks[$i] =~ '%.(\d+)s' ) {
118 0         0 $toks[$i] = ".{$1}";
119             } elsif ( $toks[$i] =~ '^%l*x$' ) {
120 54         134 $toks[$i] = '[\da-f]+';
121             }
122             } elsif ( length( $toks[$i] ) ) {
123 6348         12132 $toks[$i] = quotemeta $toks[$i];
124 6348         13223 $conlen += length( $toks[$i] );
125             }
126             }
127 3186         7535 my $lhs = join( '', @toks );
128 3186         10067 $transfmt{$header}{pat} = " s<^$lhs>\n <\Q$header\E>s\n\t&& return 1;\n";
129 3186         306376 $transfmt{$header}{len} = $conlen;
130             } else {
131 2436         7731 $transfmt{$header}{pat} = " m<^\Q$header\E> && return 1;\n";
132 2436         180652 $transfmt{$header}{len} = length($header);
133             }
134             }
135              
136 6         1819 $self->{errors} = \%errors;
137              
138             # Apply patterns in order of decreasing sum of lengths of fixed parts
139             # Seems the best way of hitting the right one.
140 6         16 my $transmo = '';
141 6         2799 for my $hdr ( sort { $transfmt{$b}{len} <=> $transfmt{$a}{len} } keys %transfmt ) {
  48381         68090  
142 5622         9466 $transmo .= $transfmt{$hdr}{pat};
143             }
144 6         1315 $transmo = "sub transmo {\n study;\n $transmo; return 0;\n}\n";
145 6         846 $self->{transmo} = $transmo;
146              
147 6         38135 return;
148             }
149              
150             sub _get_diagnostics {
151 28     28   48 my $self = shift;
152 28         62 local $_ = shift;
153 28         48 eval { transmo(); };
  28         1623  
154 28 50       78 if ($@) {
155 0         0 cluck($@);
156             }
157 28 50       207 return $self->{localized_errors}{$_} ? $self->{localized_errors}{$_} : $self->{errors}{$_};
158             }
159              
160              
161             # GOTCHAS OF "USE DIAGNOSTICS":
162             # 1. if error explanations are enabled (i.e. no '-traceonly'),
163             # consecutive numbering at the end of the error message (e.g. "(#1)",
164             # "(#2)", etc) will be appended
165             # 2. if error explanations are enabled, the original error messages
166             # will be split into two lines if they exceed 79 characters
167             # 3. if a stack trace is to be printed, the error message will have
168             # a tab prepended and will follow "Uncaught exception from user code:\n\t".
169             # This message may have been been printed already as part of the
170             # explanations.
171              
172             sub _parse_to_hash {
173 15     15   30 my $self = shift;
174 15         34 my $string = shift;
175              
176 15 50       51 if ( !$string ) {
177 0         0 carp "parse_string called without an argument";
178 0         0 return;
179             }
180              
181 15         88 my $error_pattern = qr/
182             ^\s* # optional whitespace
183             (.*) # $1 - the error message
184             \sat\s(.*) # $2 - the filename or eval
185             \sline\s(\d+) # $3 - the line number
186             (?:
187             \. # end of error message
188             |(?: # or start collecting additional information
189             (?: # option 1: we have a "near" message
190             ,\snear\s\"(.*?)# $4 - the "near" message
191             (\")? # $5 - does the near message end on this line?
192             )
193             |(?: # option 2: we have an "at" message
194             ,\sat\s(.*) # $6 - the "at" message
195             )
196             )
197             )?
198             (?:\s\(\#\d+\))? # "use diagnostics" appends "(#1)" at the end of error messages
199             $/x;
200              
201 15         27 my @error_list;
202              
203             # check if error messages were split by diagnostics
204 15         130 my @unchecked_lines = split( /\n/, $string );
205 15         35 my @checked_lines;
206              
207             # lines after the start of the stack trace
208             my @stack_trace;
209              
210 15         72 for ( my $i = 0; $i <= $#unchecked_lines; $i++ ) {
211 118         145 my $current_line = $unchecked_lines[$i];
212 118 100       291 if ( $current_line eq "Uncaught exception from user code:" ) {
    100          
213 6         31 @stack_trace = @unchecked_lines[ ++$i .. $#unchecked_lines ];
214 6         16 last;
215             } elsif ( $i == $#unchecked_lines ) {
216 9         35 push @checked_lines, $current_line;
217             } else {
218 103         133 my $next_line = $unchecked_lines[ $i + 1 ];
219 103         156 my $test_line = $current_line . " " . $next_line;
220 103 100 66     594 if ( length($current_line) <= 79
      100        
221             and length($test_line) > 79
222             and $next_line =~ /^\t.*\(\#\d+\)$/
223              
224             #and $test_line =~ $error_pattern
225             )
226             {
227 2         8 $next_line =~ s/^\s*/ /;
228 2         4 my $real_line = $current_line . $next_line;
229 2         4 push @checked_lines, $real_line;
230 2         7 $i++;
231             } else {
232 101         282 push @checked_lines, $current_line;
233             }
234             }
235             }
236              
237             # file and line number where the fatal error occurred
238 15         26 my ( $die_at_file, $die_at_line );
239              
240             # the items in the stack trace list
241 0         0 my @trace_items;
242              
243             # the fatal error(s)
244 0         0 my @stack_trace_errors;
245              
246 15 100       43 if (@stack_trace) {
247 6         27 for ( my $i = 0; $i <= $#stack_trace; $i++ ) {
248 20 100       93 if ( $stack_trace[$i] =~ /^\sat\s(.*)\sline\s(\d+)$/ ) {
249 6         21 $die_at_file = $1;
250 6         18 $die_at_line = $2;
251 6         14 @trace_items = @stack_trace[ ++$i .. $#stack_trace ];
252 6         13 last;
253             } else {
254 14         39 push @stack_trace_errors, $stack_trace[$i];
255             }
256             }
257             }
258              
259             # used to check if we are in a multi-line 'near' message
260 15         27 my $in_near;
261              
262 15         38 foreach my $line ( @checked_lines, @stack_trace_errors ) {
263              
264             # carriage returns may remain in multi-line 'near' messages and cause problems
265             # $line =~ s/\r/ /g;
266             # $line =~ s/\s+/ /g;
267 126 100       205 if ( !$in_near ) {
268 120 100       782 if ( $line =~ $error_pattern ) {
269 28         164 my %err_item = (
270             message => $1,
271             line => $3,
272             );
273 28         96 my $diagnostics = $self->_get_diagnostics($1);
274 28 50       99 if ($diagnostics) {
275 28         102 my $err_type = $self->_get_error_type($diagnostics);
276 28         82 my $err_desc = $self->_get_error_desc($err_type);
277              
278 28         63 $err_item{diagnostics} = $diagnostics;
279 28         53 $err_item{type} = $err_type;
280 28         54 $err_item{type_description} = $err_desc;
281             }
282 28         61 my $file = $2;
283 28 100       73 if ( $file =~ /^\(eval\s\d+\)$/ ) {
284 1         3 $err_item{file_msgpath} = $file;
285 1         3 $err_item{file} = "eval";
286             } else {
287 27         54 $err_item{file_msgpath} = $file;
288 27         811 $err_item{file_abspath} = File::Spec->rel2abs($file);
289 27         82 $err_item{file} = $self->_get_short_path($file);
290             }
291 28         65 my $near = $4;
292 28         45 my $near_end = $5;
293              
294 28 100       90 $err_item{at} = $6 if $6;
295              
296 28 100 100     153 if ( $near and !$near_end ) {
    100 66        
297 3         5 $in_near = ( $near . "\n" );
298             } elsif ( $near and $near_end ) {
299 1         2 $err_item{near} = $near;
300             }
301              
302 28 100 66     79 if (!grep {
  18 100       148  
303             $_->{message} eq $err_item{message}
304             and $_->{line} eq $err_item{line}
305             and $_->{file_msgpath} eq $err_item{file_msgpath}
306             } @error_list
307             )
308             {
309 22         83 push @error_list, \%err_item;
310             }
311             }
312             } else {
313 6 100       24 if ( $line =~ /^(.*)\"$/ ) {
314 3         7 $in_near .= $1;
315 3         10 $error_list[-1]->{near} = $in_near;
316 3         7 undef $in_near;
317             } else {
318 3         8 $in_near .= ( $line . "\n" );
319             }
320             }
321             }
322              
323 15 100       47 if (@trace_items) {
324 1         2 my @parsed_stack_trace;
325 1         2 foreach my $line (@trace_items) {
326 2 50       15 if ( $line =~ /^\s*(.*)\scalled\sat\s(.*)\sline\s(\d+)$/ ) {
327 2         33 my %trace_item = (
328             sub => $1,
329             file_msgpath => $2,
330             file_abspath => File::Spec->rel2abs($2),
331             file => $self->_get_short_path($2),
332             line => $3,
333             );
334 2         14 my $stack_object = Parse::ErrorString::Perl::StackItem->new( \%trace_item );
335 2         6 push @parsed_stack_trace, $stack_object;
336             }
337             }
338              
339 1         3 for ( my $i = $#error_list; $i >= 0; $i-- ) {
340 1 50 33     9 if ( $error_list[$i]->{file_msgpath} eq $die_at_file and $error_list[$i]->{line} == $die_at_line ) {
341 1         2 $error_list[$i]->{stack} = \@parsed_stack_trace;
342 1         2 last;
343             }
344             }
345             }
346              
347 15         290 return @error_list;
348             }
349              
350             sub _get_error_type {
351 28     28   51 my ( $self, $description ) = @_;
352 28 50       199 if ( $description =~ /^\(\u(\w)\|\u(\w)\W/ ) {
    50          
353 0 0       0 return wantarray ? ( $1, $2 ) : "$1|$2";
354             } elsif ( $description =~ /^\(\u(\w)\W/ ) {
355 28         144 return $1;
356             }
357             }
358              
359             sub _get_error_desc {
360 28     28   56 my ( $self, $error_type ) = @_;
361 28 50       90 if ( $error_type =~ /^\u\w$/ ) {
    0          
362 28         106 return $self->{error_desc_hash}->{$error_type};
363             } elsif ( $error_type =~ /^\u(\w)\|\u(\w)$/ ) {
364 0         0 return $self->{error_desc_hash}->{$1} . " or " . $self->{error_desc_hash}->{$2};
365             }
366             }
367              
368             sub _get_short_path {
369 29     29   48 my ( $self, $path ) = @_;
370              
371             # my ($volume, $directories, $file) = File::Spec->splitpath($filename);
372             # my @dirs = File::Spec->splitdir($directories);
373              
374 29         683 my ( $filename, $directories, $suffix ) = File::Basename::fileparse($path);
375 29 50       167 if ( $suffix eq '.pm' ) {
376 0         0 foreach my $inc_dir (@INC) {
377 0 0       0 if ( $path =~ /^\Q$_\E(.+)$/ ) {
378 0         0 return $1;
379             }
380             }
381              
382 0         0 return $path;
383              
384             } else {
385 29         127 return $filename . $suffix;
386             }
387             }
388              
389             sub _prepare_localized_diagnostics {
390 6     6   23 my $self = shift;
391 6         22 my %options = @_;
392              
393 6 50       62 return unless $options{lang};
394              
395 0           my $perldiag;
396             my $pod_filename;
397              
398 0           $perldiag = 'POD2::' . $options{lang} . '::perldiag';
399 0           $pod_filename = Pod::Find::pod_where( { -inc => 1 }, $perldiag );
400              
401 0 0         if ( !$pod_filename ) {
402 0           carp "Could not locate localised perldiag, will use perldiag in English";
403 0           return;
404             }
405              
406 0           my $parser = Pod::POM->new();
407 0           my $pom = $parser->parse_file($pod_filename);
408 0 0         if ( !$pom ) {
409 0           carp $parser->error();
410 0           return;
411             }
412              
413 0           my %localized_errors;
414 0           foreach my $item ( $pom->head1->[1]->over->[0]->item ) {
415 0           my $header = $item->title;
416              
417 0           my $content = $item->content;
418 0           $content =~ s/\s*$//;
419 0           $localized_errors{$header} = $content;
420             }
421              
422 0           $self->{localized_errors} = \%localized_errors;
423             }
424              
425             1;
426              
427             __END__