File Coverage

blib/lib/Net/Twitter/Error.pm
Criterion Covered Total %
statement 30 32 93.7
branch 4 4 100.0
condition 10 18 55.5
subroutine 10 11 90.9
pod 2 2 100.0
total 56 67 83.5


line stmt bran cond sub pod time code
1             package Net::Twitter::Error;
2             $Net::Twitter::Error::VERSION = '4.01042';
3 34     34   49706 use Moose;
  34         296848  
  34         229  
4 34     34   155879 use Try::Tiny;
  34         56  
  34         1687  
5 34     34   15362 use Devel::StackTrace;
  34         81726  
  34         2555  
6              
7             use overload (
8             # We can't use 'error' directly, because overloads are called with three
9             # arguments ($self, undef, '') resulting in an error:
10             # Cannot assign a value to a read-only accessor
11 11     11   2294     '""' => sub { shift->error },
12              
13 34         155     fallback => 1,
14 34     34   160 );
  34         44  
15              
16             has http_response => (
17                 isa => 'HTTP::Response',
18                 is => 'ro',
19                 required => 1,
20                 handles => [qw/code message/],
21             );
22              
23             has twitter_error => (
24                 is => 'ro',
25                 predicate => 'has_twitter_error',
26             );
27              
28             has stack_trace => (
29                 is => 'ro',
30                 init_arg => undef,
31                 builder => '_build_stack_trace',
32                 handles => {
33                     stack_frame => 'frame',
34                 },
35             );
36              
37             sub _build_stack_trace {
38 14     14   17     my $seen;
39 14         86     my $this_sub = (caller 0)[3];
40                 Devel::StackTrace->new(frame_filter => sub {
41 58     58   1227         my $caller = shift->{caller};
42 58   100     166         my $in_nt = $caller->[0] =~ /^Net::Twitter::/ || $caller->[3] eq $this_sub;
43 58 100 66     280         ($seen ||= $in_nt) && !$in_nt || 0;
      66        
44 14         267     });
45             }
46              
47             has error => (
48                 is => 'ro',
49                 init_arg => undef,
50                 lazy => 1,
51                 builder => '_build_error',
52             );
53              
54             sub _build_error {
55 9     9   13     my $self = shift;
56              
57 9   66     27     my $error = $self->twitter_error_text || $self->http_response->status_line;
58 9         61     my ($location) = $self->stack_frame(0)->as_string =~ /( at .*)/;
59 9   50     1160     return $error . ($location || '');
60             }
61              
62             sub twitter_error_text {
63 13     13 1 675     my $self = shift;
64             # Twitter does not return a consistent error structure, so we have to
65             # try each known (or guessed) variant to find a suitable message...
66              
67 13 100       381     return '' unless $self->has_twitter_error;
68 10         231     my $e = $self->twitter_error;
69              
70                 return ref $e eq 'HASH' && (
71             # the newest variant: array of errors
72                     exists $e->{errors}
73                         && ref $e->{errors} eq 'ARRAY'
74                         && exists $e->{errors}[0]
75                         && ref $e->{errors}[0] eq 'HASH'
76                         && exists $e->{errors}[0]{message}
77                         && $e->{errors}[0]{message}
78              
79             # it's single error variant
80                     || exists $e->{error}
81                         && ref $e->{error} eq 'HASH'
82                         && exists $e->{error}{message}
83                         && $e->{error}{message}
84              
85             # the original error structure (still applies to some endpoints)
86                     || exists $e->{error} && $e->{error}
87              
88             # or maybe it's not that deep (documentation would be helpful, here,
89             # Twitter!)
90                     || exists $e->{message} && $e->{message}
91 10   0     197     ) || ''; # punt
92             }
93              
94             sub twitter_error_code {
95 0     0 1       my $self = shift;
96              
97                 return $self->has_twitter_error
98                     && exists $self->twitter_error->{errors}
99                     && exists $self->twitter_error->{errors}[0]
100                     && exists $self->twitter_error->{errors}[0]{code}
101                     && $self->twitter_error->{errors}[0]{code}
102 0   0               || 0;
103             }
104              
105             __PACKAGE__->meta->make_immutable;
106              
107 34     34   13939 no Moose;
  34         49  
  34         210  
108              
109             1;
110              
111             __END__
112            
113             =head1 NAME
114            
115             Net::Twitter::Error - A Net::Twitter exception object
116            
117             =head1 VERSION
118            
119             version 4.01042
120            
121             =head1 SYNOPSIS
122            
123             use Scalar::Util qw/blessed/;
124             use Try::Tiny;
125            
126             my $nt = Net::Twitter->new(@options);
127            
128             my $followers = try {
129             $nt->followers;
130             }
131             catch {
132             die $_ unless blessed($_) && $_->isa('Net::Twitter::Error');
133            
134             warn "HTTP Response Code: ", $_->code, "\n",
135             "HTTP Message......: ", $_->message, "\n",
136             "Twitter error.....: ", $_->error, "\n",
137             "Stack Trace.......: ", $_->stack_trace->as_string, "\n";
138             };
139            
140             =head1 DESCRIPTION
141            
142             B<Net::Twitter::Error> encapsulates the C<HTTP::Response> and Twitter
143             error HASH (if any) resulting from a failed API call.
144            
145             =head1 METHODS
146            
147             =over 4
148            
149             =item new
150            
151             Constructs a C<Net::Twitter::Error> object. It accepts the following parameters:
152            
153             =over 4
154            
155             =item http_response
156            
157             An C<HTTP::Response> object, required.
158            
159             =item twitter_error
160            
161             The error returned by Twitter as a HASH ref. Optional, since some API errors do
162             not include a response from Twitter. They may, instead, be the result of network
163             timeouts, proxy errors, or some other problem that prevents an API response.
164            
165             =back
166            
167             =item twitter_error
168            
169             Get or set the Twitter error HASH.
170            
171             =item http_response
172            
173             Get or set the C<HTTP::Response> object.
174            
175             =item code
176            
177             Returns the HTTP response code.
178            
179             =item message
180            
181             Returns the HTTP response message.
182            
183             =item has_twitter_error
184            
185             Returns true if the object contains a Twitter error HASH.
186            
187             =item error
188            
189             Returns the C<error> value from the C<twitter_error> HASH ref if there is one.
190             Otherwise, it returns the string "[unknown]". Includes a stack trace.
191            
192             =item twitter_error_text
193            
194             Returns the C<error> value from the C<twitter_error> HASH ref if there is one.
195             Otherwise, returns an empty string
196            
197             =item twitter_error_code
198            
199             Returns the first numeric twitter error code from the JSON response body, if
200             there is one. Otherwise, it returns 0 so the result should always be safe use
201             in a numeric test.
202            
203             See L<Twitter Error Codes|https://dev.twitter.com/docs/error-codes-responses>
204             for a list of defined error codes.
205            
206             =item stack_trace
207            
208             Returns a L<Devel::StackTrace> object.
209            
210             =item stack_frame($i)
211            
212             Returns the C<$i>th stack frame as a L<Devel::StackTrace::Frame> object.
213            
214             =back
215            
216             =head1 SEE ALSO
217            
218             =over 4
219            
220             =item L<Net::Twitter>
221            
222             =back
223            
224             =head1 AUTHOR
225            
226             Marc Mims <marc@questright.com>
227            
228             =head1 LICENSE
229            
230             Copyright (c) 2016 Marc Mims
231            
232             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
233            
234             =head1 DISCLAIMER OF WARRANTY
235            
236             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
237             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
238             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
239             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
240             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
241             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
242             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
243             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
244             NECESSARY SERVICING, REPAIR, OR CORRECTION.
245            
246             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
247             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
248             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENSE, BE
249             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
250             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
251             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
252             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
253             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
254             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
255             SUCH DAMAGES.
256