File Coverage

blib/lib/Contextual/Return/Failure.pm
Criterion Covered Total %
statement 57 60 95.0
branch 26 32 81.2
condition n/a
subroutine 9 9 100.0
pod n/a
total 92 101 91.0


line stmt bran cond sub pod time code
1             package Contextual::Return::Failure;
2             our $VERSION = 0.000_003;
3              
4 31     31   114 use Contextual::Return;
  31         37  
  31         229  
5 31     31   508 BEGIN { *_in_context = *Contextual::Return::_in_context }
6              
7 31     31   113 use warnings;
  31         32  
  31         710  
8 31     31   97 use strict;
  31         34  
  31         13850  
9              
10             my %handler_for;
11              
12             sub _FAIL_WITH {
13             # Unpack and vet args...
14 4     4   446 my $flag = shift;
15 4         3 my $selector_ref;
16 4 100       9 if (ref $flag eq 'HASH') {
17 1         1 $selector_ref = $flag;
18 1         1 $flag = undef;
19             }
20             else {
21 3         2 $selector_ref = shift;
22 3 50       7 die _in_context 'Usage: FAIL_WITH $flag_opt, \%selector, @args'
23             if ref $selector_ref ne 'HASH';
24             }
25             die _in_context "Selector values must be sub refs"
26 4 50       4 if grep {ref ne 'CODE'} values %{$selector_ref};
  9         14  
  4         8  
27              
28             # Search for handler sub;
29 4         4 my $handler;
30 4 100       8 if (defined $flag) {
31             ARG:
32 3         5 while (@_) {
33 7 100       13 last ARG if shift(@_) eq $flag;
34             }
35 3         3 my $selector = shift @_;
36 3 100       5 if (ref $selector eq 'CODE') {
37 1         2 $handler = $selector;
38 1         2 @_ = ();
39             }
40             else {
41 2         4 @_ = $selector;
42             }
43             }
44              
45             SELECTION:
46 4         6 for my $selection (reverse @_) {
47 4 100       9 if (exists $selector_ref->{$selection}) {
    100          
48 2         3 $handler = $selector_ref->{$selection};
49 2         2 last SELECTION;
50             }
51             elsif ($flag) {
52 1         4 die _in_context "Invalid option: $flag => $selection";
53             }
54             }
55              
56             # (Re)set handler...
57 3 50       9 if ($handler) {
58 3         11 my $caller_loc = join '|', (CORE::caller 1)[0,1];
59 3 100       8 if (exists $handler_for{$caller_loc}) {
60 2         6 warn _in_context "FAIL handler for package ", scalar CORE::caller, " redefined";
61             }
62 3         720 $handler_for{$caller_loc} = $handler;
63             }
64             };
65              
66             sub _FAIL (;&) {
67             # Generate args...
68 20     20   969 my $arg_generator_ref = shift;
69 20         17 my @args;
70 20 100       34 if ($arg_generator_ref) {
71             package DB;
72 5         18 ()=CORE::caller(1);
73 5         11 @args = $arg_generator_ref->(@DB::args);
74             }
75              
76             # Handle user-defined failure semantics...
77 20         65 my $caller_loc = join '|', (CORE::caller 1)[0,1];
78 20 100       78 if (exists $handler_for{$caller_loc} ) {
79             # Fake out caller() and Carp...
80 10         7 local $Contextual::Return::uplevel = 1;
81              
82 10         19 return $handler_for{$caller_loc}->(@args);
83             }
84              
85 10 50       30 my $exception = @args == 1 ? $args[0]
    100          
86             : @args > 0 ? join(q{}, @args)
87             : "Call to " . (CORE::caller 1)[3] . "() failed"
88             ;
89              
90             # Join message with croak() semantics, if string...
91 10 50       18 if (!ref $exception) {
92 10         19 $exception .= _in_context @_;
93             }
94              
95             # # Check for immediate failure...
96             # use Want qw( want );
97             # return 0 if want 'BOOL';
98             # die $exception if !want 'SCALAR';
99              
100             # Return a delayed failure object...
101             return
102 2     2   4 BOOL { 0 }
103             DEFAULT {
104 8 50   8   9 if (ref $exception) {
105 0         0 my $message = "$exception";
106 0         0 $message =~ s/$/\n/;
107 0         0 die _in_context $message, "Attempted to use failure value";
108             }
109             else {
110 8         16 die _in_context $exception, "Attempted to use failure value";
111             }
112             }
113             METHOD {
114 1         5 error => sub { _in_context $exception }
115 1     1   6 }
116 10         52 }
117              
118             1;
119              
120             __END__