File Coverage

blib/lib/Data/Object/Try.pm
Criterion Covered Total %
statement 103 103 100.0
branch 18 22 81.8
condition 2 3 66.6
subroutine 24 24 100.0
pod 12 13 92.3
total 159 165 96.3


line stmt bran cond sub pod time code
1             package Data::Object::Try;
2              
3 1     1   430955 use 5.014;
  1         6  
4              
5 1     1   7 use strict;
  1         2  
  1         20  
6 1     1   5 use warnings;
  1         2  
  1         24  
7 1     1   5 use routines;
  1         1  
  1         7  
8              
9 1     1   1824 use Moo;
  1         2  
  1         6  
10 1     1   791 use Try::Tiny ();
  1         1368  
  1         146  
11              
12             our $VERSION = '2.01'; # VERSION
13              
14             # ATTRIBUTES
15              
16             has 'invocant' => (
17             is => 'ro'
18             );
19              
20             has 'arguments' => (
21             is => 'ro'
22             );
23              
24             has 'on_try' => (
25             is => 'rw'
26             );
27              
28             has 'on_catch' => (
29             is => 'rw'
30             );
31              
32             has 'on_default' => (
33             is => 'rw'
34             );
35              
36             has 'on_finally' => (
37             is => 'rw'
38             );
39              
40             # BUILD
41              
42 30     30 0 466086 method BUILD($args) {
  30         63  
  30         40  
43 30 50       113 $self->{'on_catch'} = [] if !$args->{'on_catch'};
44              
45 30         357 return $args;
46             }
47              
48             # METHODS
49              
50 27     27 1 11281 method call($callback) {
  27         72  
  27         43  
51 27         65 $self->on_try($self->callback($callback));
52              
53 27         263 return $self;
54             }
55              
56 38     38 1 65 method callback($callback) {
  38         58  
  38         54  
57 38         187 require Carp;
58              
59 38 100       151 unless (UNIVERSAL::isa($callback, 'CODE')) {
60 16 50       99 my $method = $self->invocant
61             ? $self->invocant->can($callback) : $self->can($callback);
62 16 50       40 Carp::confess(sprintf(
63             qq(Can't locate object method "%s" on package "%s"),
64             ($callback, ref $self)
65             )) if !$method;
66 16     16   62 $callback = sub { goto $method };
  16         80  
67             }
68              
69 38         147 return $callback;
70             }
71              
72 3     3 1 27 method catch($class, $callback) {
  3         8  
  3         5  
73 3         4 push @{$self->on_catch}, [$class, $self->callback($callback)];
  3         13  
74              
75 3         46 return $self;
76             }
77              
78 3     3 1 23 method default($callback) {
  3         7  
  3         6  
79 3         10 $self->on_default($self->callback($callback));
80              
81 3         44 return $self;
82             }
83              
84 29     29 1 56 method execute($callback, @args) {
  29         58  
  29         39  
85 19         53 unshift @args, @{$self->arguments}
86 29 100 66     96 if $self->arguments && @{$self->arguments};
  19         82  
87 29 100       84 unshift @args, $self->invocant
88             if $self->invocant;
89              
90 29         347 return $callback->(@args);
91             }
92              
93 3     3 1 30 method finally($callback) {
  3         7  
  3         5  
94 3         9 $self->on_finally($self->callback($callback));
95              
96 3         48 return $self;
97             }
98              
99 1     1 1 6 method maybe() {
  1         2  
100 1     1   8 $self->on_default(sub{''});
  1         4  
101              
102 1         10 return $self;
103             }
104              
105 1     1 1 6 method no_catch() {
  1         2  
106 1         8 $self->on_catch([]);
107              
108 1         10 return $self;
109             }
110              
111 1     1 1 6 method no_default() {
  1         2  
112 1         9 $self->on_default(undef);
113              
114 1         9 return $self;
115             }
116              
117 1     1 1 7 method no_finally() {
  1         2  
118 1         8 $self->on_finally(undef);
119              
120 1         11 return $self;
121             }
122              
123 1     1 1 8 method no_try() {
  1         2  
124 1         11 $self->on_try(undef);
125              
126 1         9 return $self;
127             }
128              
129 26     26 1 154 method result(@args) {
  26         56  
  26         33  
130 26         102 require Carp;
131              
132 26         42 my $returned;
133              
134             Try::Tiny::try(sub {
135 26     26   1646 my $tryer = $self->on_try;
136              
137 26         69 $returned = $self->execute($tryer, @args);
138             }, Try::Tiny::catch(sub {
139 5     5   127 my $caught = $_;
140 5         12 my $catchers = $self->on_catch;
141 5         10 my $default = $self->on_default;
142              
143 5         11 for my $catcher (@$catchers) {
144 1 50       5 if (UNIVERSAL::isa($caught, $catcher->[0])) {
145 1         20 $returned = $catcher->[1]->($caught);
146 1         9 last;
147             }
148             }
149              
150 5 100       18 if(!$returned) {
151 4 100       29 $returned = $default->($caught) if $default;
152 4 100       76 Carp::confess($caught) if not defined $returned;
153             }
154             }, Try::Tiny::finally(sub {
155 26     26   675 my $finally = $self->on_finally;
156              
157 26 100       78 $self->execute($finally, @args) if $finally;
158 26         184 })));
159              
160 24         479 return $returned;
161             }
162              
163             1;
164              
165             =encoding utf8
166              
167             =head1 NAME
168              
169             Data::Object::Try
170              
171             =cut
172              
173             =head1 ABSTRACT
174              
175             Try Class for Perl 5
176              
177             =cut
178              
179             =head1 SYNOPSIS
180              
181             use strict;
182             use warnings;
183             use routines;
184              
185             use Data::Object::Try;
186              
187             my $try = Data::Object::Try->new;
188              
189             $try->call(fun (@args) {
190             # try something
191              
192             return time;
193             });
194              
195             $try->catch('Example::Exception', fun ($caught) {
196             # caught an exception
197              
198             return;
199             });
200              
201             $try->default(fun ($caught) {
202             # catch the uncaught
203              
204             return;
205             });
206              
207             $try->finally(fun (@args) {
208             # always run after try/catch
209              
210             return;
211             });
212              
213             my @args;
214              
215             my $result = $try->result(@args);
216              
217             =cut
218              
219             =head1 DESCRIPTION
220              
221             This package provides an object-oriented interface for performing complex try/catch operations.
222              
223             =cut
224              
225             =head1 ATTRIBUTES
226              
227             This package has the following attributes:
228              
229             =cut
230              
231             =head2 arguments
232              
233             arguments(ArrayRef)
234              
235             This attribute is read-only, accepts C<(ArrayRef)> values, and is optional.
236              
237             =cut
238              
239             =head2 invocant
240              
241             invocant(Object)
242              
243             This attribute is read-only, accepts C<(Object)> values, and is optional.
244              
245             =cut
246              
247             =head2 on_catch
248              
249             on_catch(ArrayRef[CodeRef])
250              
251             This attribute is read-write, accepts C<(ArrayRef[CodeRef])> values, and is optional.
252              
253             =cut
254              
255             =head2 on_default
256              
257             on_default(CodeRef)
258              
259             This attribute is read-write, accepts C<(CodeRef)> values, and is optional.
260              
261             =cut
262              
263             =head2 on_finally
264              
265             on_finally(CodeRef)
266              
267             This attribute is read-write, accepts C<(CodeRef)> values, and is optional.
268              
269             =cut
270              
271             =head2 on_try
272              
273             on_try(CodeRef)
274              
275             This attribute is read-write, accepts C<(CodeRef)> values, and is optional.
276              
277             =cut
278              
279             =head1 METHODS
280              
281             This package implements the following methods:
282              
283             =cut
284              
285             =head2 call
286              
287             call(Str | CodeRef $arg) : Object
288              
289             The call method takes a method name or coderef, registers it as the tryable
290             routine, and returns the object. When invoked, the callback will received an
291             C if one was provided to the constructor, the default C if
292             any were provided to the constructor, and whatever arguments were provided by
293             the invocant.
294              
295             =over 4
296              
297             =item call example #1
298              
299             my $try = Data::Object::Try->new;
300              
301             $try->call(fun (@args) {
302              
303             return [@args];
304             });
305              
306             =back
307              
308             =cut
309              
310             =head2 callback
311              
312             callback(Str | CodeRef $arg) : CodeRef
313              
314             The callback method takes a method name or coderef, and returns a coderef for
315             registration. If a coderef is provided this method is mostly a passthrough.
316              
317             =over 4
318              
319             =item callback example #1
320              
321             my $try = Data::Object::Try->new;
322              
323             $try->callback(fun (@args) {
324              
325             return [@args];
326             });
327              
328             =back
329              
330             =over 4
331              
332             =item callback example #2
333              
334             package Example;
335              
336             use Moo;
337              
338             fun test(@args) {
339              
340             return [@args];
341             }
342              
343             package main;
344              
345             my $try = Data::Object::Try->new(
346             invocant => Example->new
347             );
348              
349             $try->callback('test');
350              
351             =back
352              
353             =cut
354              
355             =head2 catch
356              
357             catch(Str $isa, Str | CodeRef $arg) : Any
358              
359             The catch method takes a package or ref name, and when triggered checks whether
360             the captured exception is of the type specified and if so executes the given
361             callback.
362              
363             =over 4
364              
365             =item catch example #1
366              
367             my $try = Data::Object::Try->new;
368              
369             $try->call(fun (@args) {
370              
371             die $try;
372             });
373              
374             $try->catch('Data::Object::Try', fun (@args) {
375              
376             return [@args];
377             });
378              
379             =back
380              
381             =cut
382              
383             =head2 default
384              
385             default(Str | CodeRef $arg) : Object
386              
387             The default method takes a method name or coderef and is triggered if no
388             C conditions match the exception thrown.
389              
390             =over 4
391              
392             =item default example #1
393              
394             my $try = Data::Object::Try->new;
395              
396             $try->call(fun (@args) {
397              
398             die $try;
399             });
400              
401             $try->default(fun (@args) {
402              
403             return [@args];
404             });
405              
406             =back
407              
408             =cut
409              
410             =head2 execute
411              
412             execute(CodeRef $arg, Any @args) : Any
413              
414             The execute method takes a coderef and executes it with any given arguments.
415             When invoked, the callback will received an C if one was provided to
416             the constructor, the default C if any were provided to the
417             constructor, and whatever arguments were passed directly to this method.
418              
419             =over 4
420              
421             =item execute example #1
422              
423             my $try = Data::Object::Try->new(
424             invocant => Example->new,
425             arguments => [1,2,3]
426             );
427              
428             $try->execute(fun (@args) {
429              
430             return [@args];
431             });
432              
433             =back
434              
435             =cut
436              
437             =head2 finally
438              
439             finally(Str | CodeRef $arg) : Object
440              
441             The finally method takes a package or ref name and always executes the callback
442             after a try/catch operation. The return value is ignored. When invoked, the
443             callback will received an C if one was provided to the constructor,
444             the default C if any were provided to the constructor, and whatever
445             arguments were provided by the invocant.
446              
447             =over 4
448              
449             =item finally example #1
450              
451             my $try = Data::Object::Try->new(
452             invocant => Example->new,
453             arguments => [1,2,3]
454             );
455              
456             $try->call(fun (@args) {
457              
458             return $try;
459             });
460              
461             $try->finally(fun (@args) {
462              
463             $try->{'$finally'} = [@args];
464             });
465              
466             =back
467              
468             =cut
469              
470             =head2 maybe
471              
472             maybe() : Object
473              
474             The maybe method registers a default C condition that returns falsy,
475             i.e. an empty string, if an exception is encountered.
476              
477             =over 4
478              
479             =item maybe example #1
480              
481             my $try = Data::Object::Try->new;
482              
483             $try->call(fun (@args) {
484              
485             die $try;
486             });
487              
488             $try->maybe;
489              
490             =back
491              
492             =cut
493              
494             =head2 no_catch
495              
496             no_catch() : Object
497              
498             The no_catch method removes any configured catch conditions and returns the
499             object.
500              
501             =over 4
502              
503             =item no_catch example #1
504              
505             my $try = Data::Object::Try->new;
506              
507             $try->call(fun (@args) {
508              
509             die $try;
510             });
511              
512             $try->catch('Data::Object::Try', fun (@args) {
513              
514             return [@args];
515             });
516              
517             $try->no_catch;
518              
519             =back
520              
521             =cut
522              
523             =head2 no_default
524              
525             no_default() : Object
526              
527             The no_default method removes any configured default condition and returns the
528             object.
529              
530             =over 4
531              
532             =item no_default example #1
533              
534             my $try = Data::Object::Try->new;
535              
536             $try->call(fun (@args) {
537              
538             die $try;
539             });
540              
541             $try->default(fun (@args) {
542              
543             return [@args];
544             });
545              
546             $try->no_default;
547              
548             =back
549              
550             =cut
551              
552             =head2 no_finally
553              
554             no_finally() : Object
555              
556             The no_finally method removes any configured finally condition and returns the
557             object.
558              
559             =over 4
560              
561             =item no_finally example #1
562              
563             my $try = Data::Object::Try->new(
564             invocant => Example->new,
565             arguments => [1,2,3]
566             );
567              
568             $try->call(fun (@args) {
569              
570             return $try;
571             });
572              
573             $try->finally(fun (@args) {
574              
575             $try->{'$finally'} = [@args];
576             });
577              
578             $try->no_finally;
579              
580             =back
581              
582             =cut
583              
584             =head2 no_try
585              
586             no_try() : Object
587              
588             The no_try method removes any configured C operation and returns the
589             object.
590              
591             =over 4
592              
593             =item no_try example #1
594              
595             my $try = Data::Object::Try->new;
596              
597             $try->call(fun (@args) {
598              
599             return [@args];
600             });
601              
602             $try->no_try;
603              
604             =back
605              
606             =cut
607              
608             =head2 result
609              
610             result(Any @args) : Any
611              
612             The result method executes the try/catch/default/finally logic and returns
613             either 1) the return value from the successfully tried operation 2) the return
614             value from the successfully matched catch condition if an exception was thrown
615             3) the return value from the default catch condition if an exception was thrown
616             and no catch condition matched. When invoked, the C and C
617             callbacks will received an C if one was provided to the constructor,
618             the default C if any were provided to the constructor, and whatever
619             arguments were passed directly to this method.
620              
621             =over 4
622              
623             =item result example #1
624              
625             my $try = Data::Object::Try->new;
626              
627             $try->call(fun (@args) {
628              
629             return [@args];
630             });
631              
632             $try->result;
633              
634             =back
635              
636             =over 4
637              
638             =item result example #2
639              
640             my $try = Data::Object::Try->new;
641              
642             $try->call(fun (@args) {
643              
644             return [@args];
645             });
646              
647             $try->result(1..5);
648              
649             =back
650              
651             =cut
652              
653             =head1 AUTHOR
654              
655             Al Newkirk, C
656              
657             =head1 LICENSE
658              
659             Copyright (C) 2011-2019, Al Newkirk, et al.
660              
661             This is free software; you can redistribute it and/or modify it under the terms
662             of the The Apache License, Version 2.0, as elucidated in the L<"license
663             file"|https://github.com/iamalnewkirk/data-object-try/blob/master/LICENSE>.
664              
665             =head1 PROJECT
666              
667             L
668              
669             L
670              
671             L
672              
673             L
674              
675             L
676              
677             L
678              
679             =cut