source: perl/modules/Facebook/lib/Ouch.pm @ bbd0cf1

release-1.10release-1.9
Last change on this file since bbd0cf1 was bbd0cf1, checked in by Edward Z. Yang <ezyang@mit.edu>, 13 years ago
Bundle Ouch, AnyEvent::HTTP, and URI::Encode from CPAN Those dependencies of Facebook::Graph are not in Debian and are each single files, so we may as well just bundle them. Also update list of bundled libraries in README and drop their licenses (or the closest thing they have resembling one) into COPYING.
  • Property mode set to 100644
File size: 8.6 KB
Line 
1use strict;
2use warnings;
3package Ouch;
4BEGIN {
5  $Ouch::VERSION = '0.0401';
6}
7use Carp qw(longmess shortmess);
8use parent 'Exporter';
9use overload bool => sub {1}, q{""} => 'scalar', fallback => 1;
10
11our @EXPORT = qw(bleep ouch kiss hug barf);
12our @EXPORT_OK = qw(try throw catch catch_all caught caught_all);
13our %EXPORT_TAGS = ( traditional => [qw(try throw catch catch_all)], trytiny => [qw( throw caught caught_all )] );
14
15sub new {
16  my ($class, $code, $message, $data) = @_;
17  bless {code => $code, message => $message, data => $data, shortmess => shortmess($message), trace => longmess($message) }, $class;
18}
19
20sub try (&) {
21  my $try = shift;
22  eval { $try->() };
23  return $@;
24}
25
26sub ouch {
27  my ($code, $message, $data) = @_;
28  my $self = __PACKAGE__->new($code, $message, $data);
29  die $self;
30}
31
32sub throw {  # alias
33  ouch @_;
34}
35
36sub kiss {
37  my ($code, $e) = @_;
38  $e ||= $@;
39  if (ref $e eq 'Ouch' && $e->code eq $code) {
40    return 1;
41  }
42  return 0;
43}
44
45sub catch {
46  kiss @_;
47}
48
49sub caught {
50  kiss @_;
51}
52
53sub hug {
54  my ($e) = @_;
55  $e ||= $@;
56  return $@ ? 1 : 0;
57}
58
59sub catch_all {
60  hug @_;
61}
62
63sub caught_all {
64  hug @_;
65}
66
67sub bleep {
68  my ($e) = @_;
69  $e ||= $@;
70  if (ref $e eq 'Ouch') {
71    return $e->message;
72  }
73  else {
74    my $message = $@;
75    if ($message =~ m{^(.*)\s+at\s.*line\s\d+.}xms) {
76        return $1;
77    }
78    else {
79        return $message;
80    }
81  }
82}
83
84sub barf {
85    my ($e) = @_;
86    my $code;
87    $e ||= $@;
88    if (ref $e eq 'Ouch') {
89        $code = $e->code;
90    } 
91    else {
92        $code = 1;
93    }
94
95    print STDERR bleep($e)."\n";
96    exit $code;
97}
98
99sub scalar {
100  my $self = shift;
101  return $self->{shortmess};
102}
103
104sub trace {
105  my $self = shift;
106  return $self->{trace};
107}
108
109sub hashref {
110  my $self = shift;
111  return {
112    code    => $self->{code},
113    message => $self->{message},
114    data    => $self->{data},
115  };
116}
117
118sub code {
119  my $self = shift;
120  return $self->{code};
121}
122
123sub message {
124  my $self = shift;
125  return $self->{message};
126}
127
128sub data {
129  my $self = shift;
130  return $self->{data};
131}
132
133=head1 NAME
134
135Ouch - Exceptions that don't hurt.
136
137=head1 VERSION
138
139version 0.0401
140
141=head1 SYNOPSIS
142
143 use Ouch;
144
145 eval { ouch(404, 'File not found.'); };
146
147 if (kiss 404) {
148   check_elsewhere();
149 }
150
151 say $@;           # These two lines do the
152 say $@->scalar;   # same thing.
153
154=head1 DESCRIPTION
155
156Ouch provides a class for exception handling that doesn't require a lot of boilerplate, nor any up front definition. If L<Exception::Class>
157is working for you, great! But if you want something that is faster, easier to use, requires less typing, and has no prereqs, but still gives
158you much of that same functionality, then Ouch is for you.
159
160=head2 Why another exception handling module?
161
162It really comes down to L<Carp> isn't enough for me, and L<Exception::Class> does what I want but makes me type way too much. Also, I tend to work on a lot of protocol-based systems that use error codes (HTTP, FTP, SMTP, JSON-RPC) rather than error classes, so that feels more natural to me. Consider the difference between these:
163
164B<Ouch>
165
166 use Ouch;
167 ouch 404, 'File not found.', 'file';
168
169B<Exception::Class>
170
171 use Exception::Class (
172    'FileNotFound' => {
173        fields  => [ 'code', 'field' ],
174    },
175 );
176 FileNotFound->throw( error => 'File not found.', code => 404, field => 'file' );
177
178And if you want to catch the exception you're looking at:
179
180B<Ouch>
181
182 if (kiss 404) {
183   # do something
184 }
185
186B<Exception::Class>
187
188 my $e;
189 if ($e = Exception::Class->caught('FileNotFound')) {
190   # do something
191 }
192
193Those differences may not seem like a lot, but over any substantial program with lots of exceptions it can become a big deal.
194
195=head2 Usage
196
197Most of the time, all you need to do is:
198
199 ouch $code, $message, $data;
200 ouch -32700, 'Parse error.', $request; # JSON-RPC 2.0 error
201 ouch 441, 'You need to specify an email address.', 'email'; # form processing error
202 ouch 'missing_param', 'You need to specify an email address.', 'email';
203
204You can also go long form if you prefer:
205
206 die Ouch->new($code, $message, $data);
207
208=head2 Functional Interface
209
210=head3 ouch
211
212Some nice sugar instead of using the object oriented interface.
213
214 ouch 2121, 'Did not do the big thing.';
215
216=over
217
218=item code
219
220An error code. An integer or string representing error type. Try to stick to codes used in whatever domain you happen to be working in. HTTP Status codes. JSON-RPC error codes, etc.
221
222=item message
223
224A human readable error message.
225
226=item data
227
228Optional. Anything you want to attach to the exception to help a developer catching it decide what to do. For example, if you're doing form processing, you might want this to be the name of the field that caused the exception.
229
230B<WARNING:> Do not include objects or code refs in your data. This should only be stuff that is easily serializable like scalars, array refs, and hash refs.
231
232=back
233
234=head3 kiss
235
236Some nice sugar to trap an Ouch.
237
238 if (kiss $code) {
239    # make it go
240 }
241
242=over
243
244=item code
245
246The code you're looking for.
247
248=item exception
249
250Optional. If you like you can pass the exception into C<kiss>. If not, it will just use whatever is in C<$@>. You might want to do this if you've saved the exception before running another C<eval>, for example.
251
252=back
253
254
255=head3 hug
256
257Some nice sugar to trap any exception.
258
259 if (hug) {
260   # make it stop
261 }
262
263=over
264
265=item exception
266
267Optional. If you like you can pass the exception into C<hug>. If not, it will just use whatever is in C<$@>.
268
269=back
270
271
272=head3 bleep
273
274A little sugar to make exceptions human friendly. Returns a clean error message from any exception, including an Ouch.
275
276 File not found.
277
278Rather than:
279
280 File not found. at /Some/File.pm line 63.
281
282=over
283
284=item exception
285
286Optional. If you like you can pass the exception into C<bleep>. If not, it will just use whatever is in C<$@>.
287
288=back
289
290=head3
291
292Calls C<bleep>, and then exits with error code
293
294=over
295
296=item exception
297
298Optional. You can pass an exception into C<barf> which then gets passed to C<bleep> otherwise it will use whatever's in C<$@>
299
300=back
301
302
303=head2 Object-Oriented Interface
304
305=head3 new
306
307Constructor for the object-oriented interface. Takes the same parameters as C<ouch>.
308
309 Ouch->new($code, $message, $data);
310
311=head3 scalar
312
313Returns the scalar form of the error message:
314
315 Crap! at /Some/File.pm line 43.
316
317Just as if you had done:
318
319 die 'Crap!';
320
321Rather than:
322
323 ouch $code, 'Crap!';
324
325=head3 trace
326
327Call this if you want the full stack trace that lead up to the ouch.
328
329=head3 hashref
330
331Returns a formatted hash reference of the exception, which can be useful for handing off to a serializer like L<JSON>.
332
333 {
334   code     => $code,
335   message  => $message,
336   data     => $data,
337 }
338
339=head3 code
340
341Returns the C<code> passed into the constructor.
342
343=head3 message
344
345Returns the C<messsage> passed into the constructor.
346
347=head3 data
348
349Returns the C<data> passed into the constructor.
350
351=head2 Traditional Interface
352
353Some people just can't bring themselves to use the sugary cuteness of Ouch. For them there is the C<:traditional> interface. Here's how it works:
354
355 use Ouch qw(:traditional);
356
357 my $e = try {
358   throw 404, 'File not found.';
359 };
360
361 if ( catch 404, $e ) {
362   # do the big thing
363 }
364 elsif ( catch_all $e ) {
365   # make it stop
366 }
367 else {
368   # make it go
369 }
370
371B<NOTE:> C<try> also populates C<$@>, and C<catch> and C<catch_all> will also use C<$@> if you don't specify an exception.
372
373=head3 try
374
375Returns an exception. Is basically just a nice wrapper around C<eval>.
376
377=over
378
379=item block
380
381Try accepts a code ref, anonymous subroutine, or a block.
382
383B<NOTE:> You need a semi-colon at the end of a C<try> block.
384
385=back
386
387=head3 throw
388
389Works exactly like C<ouch>. See C<ouch> for details.
390
391=head3 catch
392
393Works exactly like C<kiss>. See C<kiss> for details.
394
395=head3 catch_all
396
397Works exactly like C<hug>. See C<hug> for details.
398
399=head2 Try::Tiny
400
401Many Ouch users, like to use Ouch with L<Try::Tiny>, and some of them are sticks in the mud who can't bring themselves to C<ouch> and C<kiss>, and don't like that C<:traditional> walks all over C<try> and C<catch> For them, there is the C<:trytiny> interface. Here's how it works:
402
403 use Try::Tiny;
404 use Ouch qw(:trytiny);
405
406 try {
407    throw(404, 'File not found!';
408 }
409 catch {
410    if (caught($_)) {
411        # do something
412    }
413    else {
414        throw($_); # rethrow
415    }
416 };
417
418
419=head1 SUPPORT
420
421=over
422
423=item Repository
424
425L<http://github.com/rizen/Ouch>
426
427=item Bug Reports
428
429L<http://github.com/rizen/Ouch/issues>
430
431=back
432
433
434=head1 SEE ALSO
435
436If you're looking for something lighter, check out L<Carp> that ships with Perl. Or if you're looking for something heavier check out L<Exception::Class>.
437
438=head1 AUTHOR
439
440JT Smith <jt_at_plainblack_dot_com>
441
442=head1 LEGAL
443
444Ouch is Copyright 2011 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
445
446=cut
447
4481;
Note: See TracBrowser for help on using the repository browser.