File Coverage

lib/Leyland/Exception.pm
Criterion Covered Total %
statement 6 17 35.2
branch 0 8 0.0
condition n/a
subroutine 2 7 28.5
pod 5 5 100.0
total 13 37 35.1


line stmt bran cond sub pod time code
1             package Leyland::Exception;
2              
3             # ABSTRACT: Throwable class for Leyland application exceptions
4              
5 1     1   7 use Moo;
  1         3  
  1         9  
6 1     1   412 use namespace::clean;
  1         2  
  1         11  
7              
8             =head1 NAME
9              
10             Leyland::Exception - Throwable class for Leyland application exceptions
11              
12             =head1 SYNOPSIS
13              
14             # in your controllers:
15              
16             # throw a simple exception
17             $c->exception({ code => 400, error => "You need to give me your name" })
18             unless $c->params->{name};
19              
20             # you can even render the error according to the requested media type
21             create_something()
22             || $c->exception({
23             code => 500,
24             error => "Man, I have no idea what went wrong",
25             mimes => {
26             'text/html' => 'error.html',
27             'application/json' => 'error.json',
28             },
29             });
30              
31             # or you can create an error that redirects (don't do this unless
32             # you have a good reason to, you'd most likely want to use
33             # $c->res->redirect to redirect requests). The only place where
34             # this should be acceptable is inside controller methods such
35             # as auto() and pre_route(), where redirecting responses is not
36             # yet possible.
37             $c->exception({
38             code => 303,
39             error => "The resource you're requesting is available at a different location",
40             location => $c->uri_for('/some_other_place'),
41             });
42              
43             =head1 DESCRIPTION
44              
45             This module provides L applications the ability to throw HTTP exceptions
46             in a consistent and standard way. Leyland applications are meant to throw
47             standard HTTP errors, like "404 Not Found", "400 Bad Request", "500 Internal
48             Server Error", etc. Check out L
49             for a list of HTTP status codes and their descriptions/use cases (the
50             4xx and 5xx family of status codes are most relevant).
51              
52             When your application throws a Leyland::Exception, it is caught and automatically
53             serialized to a format the request accepts (or text if the client doesn't
54             accept anything we support). You can, however, render the errors into
55             views with your application's view class (like L),
56             mostly useful for rendering HTML representations of errors inside your
57             application's layout, thus preserving the design of your application even
58             when throwing errors.
59              
60             While you can use this class to throw errors with any HTTP status code,
61             you really only should do this with the 4xx and 5xx family of status codes.
62             You can, however, throw errors with a 3xx status code, in which case you
63             are also expected to provide a URI to redirect to. You should only use this
64             if you have a good reason to, as it is much more proper to redirect using
65             C<< $c->res->redirect >> (see L) for more information.
66              
67             Note that you don't use this class directly. Instead, to throw exceptions,
68             use C in L.
69              
70             If your application throws an error without calling the C
71             method just mentioned, it will still be caught and automatically turned
72             into a 500 Internal Server Error. This makes the most sense, as such errors
73             are most likely to be runtime errors thrown by modules your application
74             uses.
75              
76             =head1 CONSUMES
77              
78             L
79              
80             =head1 ATTRIBUTES
81              
82             =head2 code
83              
84             The HTTP status code of the error. Required.
85              
86             =head2 error
87              
88             An error message describing the error that occured. Optional.
89              
90             =head2 location
91              
92             A URI to redirect to if this is a redirecting exception.
93              
94             =head2 mimes
95              
96             A hash-ref of media types and template names to use for rendering the
97             error.
98              
99             =head2 use_layout
100              
101             A boolean value indicating whether to render the errors inside a layout
102             view (if exception has the "mimes" attribute). Defaults to true.
103              
104             =head2 previous_exception
105              
106             Consumed from L.
107              
108             =cut
109              
110             with 'Throwable';
111              
112             has 'code' => (
113             is => 'ro',
114             isa => sub { die "code must be an integer" unless $_[0] =~ m/^\d+$/ },
115             required => 1
116             );
117              
118             has 'error' => (
119             is => 'ro',
120             isa => sub { die "error must be a scalar" if ref $_[0] },
121             predicate => 'has_error',
122             writer => '_set_error'
123             );
124              
125             has 'location' => (
126             is => 'ro',
127             isa => sub { die "location must be a scalar" if ref $_[0] },
128             predicate => 'has_location'
129             );
130              
131             has 'mimes' => (
132             is => 'ro',
133             isa => sub { die "mimes must be a hash-ref" unless ref $_[0] && ref $_[0] eq 'HASH' },
134             predicate => 'has_mimes'
135             );
136              
137             has 'use_layout' => (
138             is => 'ro',
139             default => sub { 1 }
140             );
141              
142             =head1 OBJECT METHODS
143              
144             =head2 has_error()
145              
146             Returns a true value if the "error" attribute has a value.
147              
148             =head2 has_location()
149              
150             Returns a true value if the "location" attribute has a value.
151              
152             =head2 has_mimes()
153              
154             Returns a true value if the "mimes" attribute has a value.
155              
156             =head2 has_mime( $mime )
157              
158             Returns a true value if the "mimes" attribute has a value for the provided
159             mime type.
160              
161             =cut
162              
163             sub has_mime {
164 0     0 1   my ($self, $mime) = @_;
165              
166 0 0         return unless $self->has_mimes;
167              
168 0           return exists $self->mimes->{$mime};
169             }
170              
171             =head2 mime( $mime )
172              
173             Returns the value of provided mime type from the "mimes" attribute, or
174             C if it doesn't exist.
175              
176             =cut
177              
178             sub mime {
179 0     0 1   my ($self, $mime) = @_;
180              
181 0 0         return unless $self->has_mime($mime);
182              
183 0           return $self->mimes->{$mime};
184             }
185              
186             =head2 name()
187              
188             Returns the name of the exception. For example, if the error status code
189             is 404, the name will be "Not Found".
190              
191             =cut
192              
193             sub name {
194 0 0   0 1   $Leyland::CODES->{$_[0]->code} || 'Internal Server Error';
195             }
196              
197             =head2 hash()
198              
199             Returns a hash-ref representation of the error. This hash-ref will have
200             the keys C (which will hold the exception code and the exception
201             name, separated by a space, e.g. C<404 Not Found>), and C, which
202             will hold the error message.
203              
204             =cut
205              
206             sub hash {
207 0     0 1   my $self = shift;
208              
209             return {
210 0           error => $self->code.' '.$self->name,
211             message => $self->error
212             };
213             }
214              
215             =head1 INTERNAL METHODS
216              
217             The following methods are only to be used internally.
218              
219             =head2 BUILD()
220              
221             =cut
222              
223             sub BUILD {
224 0     0 1   my $self = shift;
225              
226 0 0         $self->_set_error($self->code.' '.$self->name)
227             unless $self->has_error;
228             }
229              
230             =head1 AUTHOR
231              
232             Ido Perlmuter, C<< >>
233              
234             =head1 BUGS
235              
236             Please report any bugs or feature requests to C, or through
237             the web interface at L. I will be notified, and then you'll
238             automatically be notified of progress on your bug as I make changes.
239              
240             =head1 SUPPORT
241              
242             You can find documentation for this module with the perldoc command.
243              
244             perldoc Leyland::Exception
245              
246             You can also look for information at:
247              
248             =over 4
249              
250             =item * RT: CPAN's request tracker
251              
252             L
253              
254             =item * AnnoCPAN: Annotated CPAN documentation
255              
256             L
257              
258             =item * CPAN Ratings
259              
260             L
261              
262             =item * Search CPAN
263              
264             L
265              
266             =back
267              
268             =head1 LICENSE AND COPYRIGHT
269              
270             Copyright 2010-2014 Ido Perlmuter.
271              
272             This program is free software; you can redistribute it and/or modify it
273             under the terms of either: the GNU General Public License as published
274             by the Free Software Foundation; or the Artistic License.
275              
276             See http://dev.perl.org/licenses/ for more information.
277              
278             =cut
279              
280             1;