File Coverage

lib/Neo4j/Error.pm
Criterion Covered Total %
statement 72 72 100.0
branch 40 40 100.0
condition 36 36 100.0
subroutine 19 19 100.0
pod 12 12 100.0
total 179 179 100.0


line stmt bran cond sub pod time code
1 5     5   380343 use v5.10;
  5         40  
2 5     5   28 use strict;
  5         6  
  5         104  
3 5     5   21 use warnings;
  5         9  
  5         256  
4              
5             package Neo4j::Error;
6             # ABSTRACT: Common Neo4j exception representations
7             $Neo4j::Error::VERSION = '0.01';
8              
9 5     5   33 use List::Util 1.33 qw(first none);
  5         88  
  5         710  
10 5     5   3138 use Module::Load qw(load);
  5         5960  
  5         33  
11              
12             my @SOURCES = qw( Server Network Internal Usage );
13             my @KEYS = qw(
14             as_string
15             category
16             classification
17             code
18             is_retryable
19             message
20             raw
21             related
22             source
23             title
24             trace
25             );
26              
27              
28             sub _croak {
29 18     18   94 require Carp;
30 18         172 Carp::croak(@_);
31             }
32              
33              
34             sub new {
35 53     53 1 84014 my ($class, $source, $info, @extra) = @_;
36            
37 53 100       164 _croak "Call as instance method unsupported for %s->new()", __PACKAGE__ if ref $class ne '';
38 52 100 100     216 _croak sprintf "Source param required for %s->new()", __PACKAGE__ unless $source && ref $source eq '';
39 50 100       101 if ($class eq __PACKAGE__) {
40 42     96   286 $class = first { $_ eq $source } @SOURCES;
  96         219  
41 42 100       168 _croak sprintf "Source '%s' is unsupported for %s->new()", $source, __PACKAGE__ unless $class;
42 38         98 $class = __PACKAGE__ . "::$class";
43 38         104 load $class;
44             }
45             else { # subclass
46 8 100       78 _croak sprintf "Class %s fails to implement source()", $class unless $class->can('source');
47 7 100       23 _croak sprintf "Ambiguous source %s for %s", $source, $class if $class->source ne $source;
48             }
49            
50 44 100 100     2459 if ($info && ref $info eq '') {
    100          
51 6         31 $info = { as_string => '' . $info };
52             }
53             elsif (ref $info ne 'HASH') {
54 2         10 _croak sprintf "Hashref or string required for %s->new()", $class;
55             }
56 42 100       111 _croak "Too many arguments for $class->new()" if @extra;
57            
58 40         96 my $self = bless {}, $class;
59 40         424 $self->{$_} = $info->{$_} for @KEYS;
60            
61 40         2128 require Devel::StackTrace;
62 40   100     13987 my $trace_config = $info->{trace} // {};
63 40         82 $trace_config->{skip_frames}++;
64 40   100     189 $trace_config->{message} //= $self->as_string;
65 40         179 $self->{trace} = Devel::StackTrace->new(%$trace_config);
66            
67 40         12126 return $self;
68             }
69              
70              
71             sub append_new {
72 12     12 1 12684 my ($self, $source, $related, @extra) = @_;
73            
74 12 100 100     65 _croak sprintf "Source param required for %s->append_new()", __PACKAGE__ unless $source && ref $source eq '';
75 10 100 100     78 _croak sprintf "Ambiguous source %s for %s", $source, $self if ref $self eq '' && $self->can('source') && $self->source ne $source;
      100        
76            
77 9 100 100     45 if ($related && ref $related eq '') {
    100          
78 1         4 $related = { as_string => '' . $related };
79             }
80             elsif (ref $related ne 'HASH') {
81 2         6 _croak sprintf "Hashref or string required for %s->append_new()", __PACKAGE__;
82             }
83            
84 7 100       16 my $class = ref $self eq '' ? $self : __PACKAGE__;
85 7         18 $related->{trace}{skip_frames}++;
86 7         16 $related = $class->new($source => $related, @extra);
87 4 100       41 return $related if ref $self eq ''; # if called as class method, behave just like new()
88            
89 1         3 my $tail = $self;
90 1         4 $tail = $tail->{related} while $tail->{related};
91 1         2 $tail->{related} = $related;
92 1         6 return $self;
93             }
94              
95              
96             sub as_string {
97 61     61 1 116 my ($self) = @_;
98            
99 61         94 my $str = $self->{as_string};
100 61 100       390 return $str if defined $str;
101            
102 29         68 my $code = $self->code;
103 29         84 my $message = $self->message;
104 29 100 100     105 $str = sprintf "%s: %s", $code, $message if $code && $message;
105 29 100 100     92 $str = sprintf "%s %s", ref $self, $code if $code && ! $message;
106 29 100 100     94 $str = sprintf "%s", $message if ! $code && $message;
107 29 100       71 $str = $self->trace unless $str; # last resort
108 29         92 return $self->{as_string} = $str;
109             }
110              
111              
112 18   100 18 1 74 sub message { shift->{message} // '' }
113 18   100 18 1 81 sub code { shift->{code} // '' }
114 3     3 1 20 sub classification { '' }
115 3     3 1 14 sub category { '' }
116 3     3 1 16 sub title { '' }
117 2     2 1 13 sub is_retryable { !!0 }
118              
119 6     6 1 37 sub related { shift->{related} }
120              
121 2     2 1 8 sub raw { shift->{raw} }
122 21     21 1 2599 sub trace { shift->{trace} }
123              
124              
125             1;
126              
127             __END__