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   32850 use 5.014;
  1         3  
4              
5 1     1   4 use strict;
  1         1  
  1         17  
6 1     1   3 use warnings;
  1         2  
  1         18  
7 1     1   4 use routines;
  1         1  
  1         5  
8              
9 1     1   1422 use Moo;
  1         1  
  1         5  
10 1     1   257 use Try::Tiny ();
  1         1  
  1         105  
11              
12             our $VERSION = '2.02'; # 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 15     15 0 167951 method BUILD($args) {
  15         27  
  15         18  
43 15 50       47 $self->{'on_catch'} = [] if !$args->{'on_catch'};
44              
45 15         232 return $args;
46             }
47              
48             # METHODS
49              
50 12     12 1 73 method call($callback) {
  12         20  
  12         28  
51 12         25 $self->on_try($self->callback($callback));
52              
53 12         172 return $self;
54             }
55              
56 23     23 1 32 method callback($callback) {
  23         30  
  23         23  
57 23         75 require Carp;
58              
59 23 100       67 unless (UNIVERSAL::isa($callback, 'CODE')) {
60 1 50       13 my $method = $self->invocant
61             ? $self->invocant->can($callback) : $self->can($callback);
62 1 50       4 Carp::confess(sprintf(
63             qq(Can't locate object method "%s" on package "%s"),
64             ($callback, ref $self)
65             )) if !$method;
66 1     1   5 $callback = sub { goto $method };
  1         864  
67             }
68              
69 23         75 return $callback;
70             }
71              
72 3     3 1 18 method catch($class, $callback) {
  3         8  
  3         4  
73 3         3 push @{$self->on_catch}, [$class, $self->callback($callback)];
  3         10  
74              
75 3         37 return $self;
76             }
77              
78 3     3 1 19 method default($callback) {
  3         5  
  3         4  
79 3         7 $self->on_default($self->callback($callback));
80              
81 3         34 return $self;
82             }
83              
84 14     14 1 23 method execute($callback, @args) {
  14         23  
  14         14  
85 4         10 unshift @args, @{$self->arguments}
86 14 100 66     36 if $self->arguments && @{$self->arguments};
  4         15  
87 14 100       32 unshift @args, $self->invocant
88             if $self->invocant;
89              
90 14         257 return $callback->(@args);
91             }
92              
93 3     3 1 19 method finally($callback) {
  3         8  
  3         3  
94 3         8 $self->on_finally($self->callback($callback));
95              
96 3         36 return $self;
97             }
98              
99 1     1 1 5 method maybe() {
  1         2  
100 1     1   5 $self->on_default(sub{''});
  1         3  
101              
102 1         8 return $self;
103             }
104              
105 1     1 1 5 method no_catch() {
  1         2  
106 1         6 $self->on_catch([]);
107              
108 1         7 return $self;
109             }
110              
111 1     1 1 5 method no_default() {
  1         2  
112 1         6 $self->on_default(undef);
113              
114 1         7 return $self;
115             }
116              
117 1     1 1 5 method no_finally() {
  1         2  
118 1         6 $self->on_finally(undef);
119              
120 1         8 return $self;
121             }
122              
123 1     1 1 5 method no_try() {
  1         2  
124 1         5 $self->on_try(undef);
125              
126 1         6 return $self;
127             }
128              
129 11     11 1 5049 method result(@args) {
  11         20  
  11         12  
130 11         39 require Carp;
131              
132 11         14 my $returned;
133              
134             Try::Tiny::try(sub {
135 11     11   530 my $tryer = $self->on_try;
136              
137 11         23 $returned = $self->execute($tryer, @args);
138             }, Try::Tiny::catch(sub {
139 5     5   96 my $caught = $_;
140 5         12 my $catchers = $self->on_catch;
141 5         9 my $default = $self->on_default;
142              
143 5         9 for my $catcher (@$catchers) {
144 1 50       4 if (UNIVERSAL::isa($caught, $catcher->[0])) {
145 1         16 $returned = $catcher->[1]->($caught);
146 1         7 last;
147             }
148             }
149              
150 5 100       15 if(!$returned) {
151 4 100       23 $returned = $default->($caught) if $default;
152 4 100       56 Carp::confess($caught) if not defined $returned;
153             }
154             }, Try::Tiny::finally(sub {
155 11     11   163 my $finally = $self->on_finally;
156              
157 11 100       26 $self->execute($finally, @args) if $finally;
158 11         74 })));
159              
160 9         165 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<invocant> if one was provided to the constructor, the default C<arguments> 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             use routines;
300              
301             my $try = Data::Object::Try->new;
302              
303             $try->call(fun (@args) {
304              
305             return [@args];
306             });
307              
308             =back
309              
310             =cut
311              
312             =head2 callback
313              
314             callback(Str | CodeRef $arg) : CodeRef
315              
316             The callback method takes a method name or coderef, and returns a coderef for
317             registration. If a coderef is provided this method is mostly a passthrough.
318              
319             =over 4
320              
321             =item callback example #1
322              
323             use routines;
324              
325             my $try = Data::Object::Try->new;
326              
327             $try->callback(fun (@args) {
328              
329             return [@args];
330             });
331              
332             =back
333              
334             =over 4
335              
336             =item callback example #2
337              
338             package Example;
339              
340             use Moo;
341             use routines;
342              
343             fun test(@args) {
344              
345             return [@args];
346             }
347              
348             package main;
349              
350             my $try = Data::Object::Try->new(
351             invocant => Example->new
352             );
353              
354             $try->callback('test');
355              
356             =back
357              
358             =cut
359              
360             =head2 catch
361              
362             catch(Str $isa, Str | CodeRef $arg) : Any
363              
364             The catch method takes a package or ref name, and when triggered checks whether
365             the captured exception is of the type specified and if so executes the given
366             callback.
367              
368             =over 4
369              
370             =item catch example #1
371              
372             use routines;
373              
374             my $try = Data::Object::Try->new;
375              
376             $try->call(fun (@args) {
377              
378             die $try;
379             });
380              
381             $try->catch('Data::Object::Try', fun (@args) {
382              
383             return [@args];
384             });
385              
386             =back
387              
388             =cut
389              
390             =head2 default
391              
392             default(Str | CodeRef $arg) : Object
393              
394             The default method takes a method name or coderef and is triggered if no
395             C<catch> conditions match the exception thrown.
396              
397             =over 4
398              
399             =item default example #1
400              
401             use routines;
402              
403             my $try = Data::Object::Try->new;
404              
405             $try->call(fun (@args) {
406              
407             die $try;
408             });
409              
410             $try->default(fun (@args) {
411              
412             return [@args];
413             });
414              
415             =back
416              
417             =cut
418              
419             =head2 execute
420              
421             execute(CodeRef $arg, Any @args) : Any
422              
423             The execute method takes a coderef and executes it with any given arguments.
424             When invoked, the callback will received an C<invocant> if one was provided to
425             the constructor, the default C<arguments> if any were provided to the
426             constructor, and whatever arguments were passed directly to this method.
427              
428             =over 4
429              
430             =item execute example #1
431              
432             use routines;
433              
434             my $try = Data::Object::Try->new(
435             invocant => Example->new,
436             arguments => [1,2,3]
437             );
438              
439             $try->execute(fun (@args) {
440              
441             return [@args];
442             });
443              
444             =back
445              
446             =cut
447              
448             =head2 finally
449              
450             finally(Str | CodeRef $arg) : Object
451              
452             The finally method takes a package or ref name and always executes the callback
453             after a try/catch operation. The return value is ignored. When invoked, the
454             callback will received an C<invocant> if one was provided to the constructor,
455             the default C<arguments> if any were provided to the constructor, and whatever
456             arguments were provided by the invocant.
457              
458             =over 4
459              
460             =item finally example #1
461              
462             use routines;
463              
464             my $try = Data::Object::Try->new(
465             invocant => Example->new,
466             arguments => [1,2,3]
467             );
468              
469             $try->call(fun (@args) {
470              
471             return $try;
472             });
473              
474             $try->finally(fun (@args) {
475              
476             $try->{'$finally'} = [@args];
477             });
478              
479             =back
480              
481             =cut
482              
483             =head2 maybe
484              
485             maybe() : Object
486              
487             The maybe method registers a default C<catch> condition that returns falsy,
488             i.e. an empty string, if an exception is encountered.
489              
490             =over 4
491              
492             =item maybe example #1
493              
494             use routines;
495              
496             my $try = Data::Object::Try->new;
497              
498             $try->call(fun (@args) {
499              
500             die $try;
501             });
502              
503             $try->maybe;
504              
505             =back
506              
507             =cut
508              
509             =head2 no_catch
510              
511             no_catch() : Object
512              
513             The no_catch method removes any configured catch conditions and returns the
514             object.
515              
516             =over 4
517              
518             =item no_catch example #1
519              
520             use routines;
521              
522             my $try = Data::Object::Try->new;
523              
524             $try->call(fun (@args) {
525              
526             die $try;
527             });
528              
529             $try->catch('Data::Object::Try', fun (@args) {
530              
531             return [@args];
532             });
533              
534             $try->no_catch;
535              
536             =back
537              
538             =cut
539              
540             =head2 no_default
541              
542             no_default() : Object
543              
544             The no_default method removes any configured default condition and returns the
545             object.
546              
547             =over 4
548              
549             =item no_default example #1
550              
551             use routines;
552              
553             my $try = Data::Object::Try->new;
554              
555             $try->call(fun (@args) {
556              
557             die $try;
558             });
559              
560             $try->default(fun (@args) {
561              
562             return [@args];
563             });
564              
565             $try->no_default;
566              
567             =back
568              
569             =cut
570              
571             =head2 no_finally
572              
573             no_finally() : Object
574              
575             The no_finally method removes any configured finally condition and returns the
576             object.
577              
578             =over 4
579              
580             =item no_finally example #1
581              
582             use routines;
583              
584             my $try = Data::Object::Try->new(
585             invocant => Example->new,
586             arguments => [1,2,3]
587             );
588              
589             $try->call(fun (@args) {
590              
591             return $try;
592             });
593              
594             $try->finally(fun (@args) {
595              
596             $try->{'$finally'} = [@args];
597             });
598              
599             $try->no_finally;
600              
601             =back
602              
603             =cut
604              
605             =head2 no_try
606              
607             no_try() : Object
608              
609             The no_try method removes any configured C<try> operation and returns the
610             object.
611              
612             =over 4
613              
614             =item no_try example #1
615              
616             use routines;
617              
618             my $try = Data::Object::Try->new;
619              
620             $try->call(fun (@args) {
621              
622             return [@args];
623             });
624              
625             $try->no_try;
626              
627             =back
628              
629             =cut
630              
631             =head2 result
632              
633             result(Any @args) : Any
634              
635             The result method executes the try/catch/default/finally logic and returns
636             either 1) the return value from the successfully tried operation 2) the return
637             value from the successfully matched catch condition if an exception was thrown
638             3) the return value from the default catch condition if an exception was thrown
639             and no catch condition matched. When invoked, the C<try> and C<finally>
640             callbacks will received an C<invocant> if one was provided to the constructor,
641             the default C<arguments> if any were provided to the constructor, and whatever
642             arguments were passed directly to this method.
643              
644             =over 4
645              
646             =item result example #1
647              
648             use routines;
649              
650             my $try = Data::Object::Try->new;
651              
652             $try->call(fun (@args) {
653              
654             return [@args];
655             });
656              
657             $try->result;
658              
659             =back
660              
661             =over 4
662              
663             =item result example #2
664              
665             use routines;
666              
667             my $try = Data::Object::Try->new;
668              
669             $try->call(fun (@args) {
670              
671             return [@args];
672             });
673              
674             $try->result(1..5);
675              
676             =back
677              
678             =cut
679              
680             =head1 AUTHOR
681              
682             Al Newkirk, C<awncorp@cpan.org>
683              
684             =head1 LICENSE
685              
686             Copyright (C) 2011-2019, Al Newkirk, et al.
687              
688             This is free software; you can redistribute it and/or modify it under the terms
689             of the The Apache License, Version 2.0, as elucidated in the L<"license
690             file"|https://github.com/iamalnewkirk/data-object-try/blob/master/LICENSE>.
691              
692             =head1 PROJECT
693              
694             L<Wiki|https://github.com/iamalnewkirk/data-object-try/wiki>
695              
696             L<Project|https://github.com/iamalnewkirk/data-object-try>
697              
698             L<Initiatives|https://github.com/iamalnewkirk/data-object-try/projects>
699              
700             L<Milestones|https://github.com/iamalnewkirk/data-object-try/milestones>
701              
702             L<Contributing|https://github.com/iamalnewkirk/data-object-try/blob/master/CONTRIBUTE.md>
703              
704             L<Issues|https://github.com/iamalnewkirk/data-object-try/issues>
705              
706             =cut