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   115 use Contextual::Return;
  31         38  
  31         211  
5 31     31   531 BEGIN { *_in_context = *Contextual::Return::_in_context }
6              
7 31     31   120 use warnings;
  31         33  
  31         736  
8 31     31   99 use strict;
  31         35  
  31         14419  
9              
10             my %handler_for;
11              
12             sub _FAIL_WITH {
13             # Unpack and vet args...
14 4     4   669 my $flag = shift;
15 4         3 my $selector_ref;
16 4 100       11 if (ref $flag eq 'HASH') {
17 1         11 $selector_ref = $flag;
18 1         1 $flag = undef;
19             }
20             else {
21 3         3 $selector_ref = shift;
22 3 50       8 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       5 if grep {ref ne 'CODE'} values %{$selector_ref};
  9         15  
  4         10  
27              
28             # Search for handler sub;
29 4         2 my $handler;
30 4 100       9 if (defined $flag) {
31             ARG:
32 3         6 while (@_) {
33 7 100       15 last ARG if shift(@_) eq $flag;
34             }
35 3         4 my $selector = shift @_;
36 3 100       7 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         7 for my $selection (reverse @_) {
47 4 100       11 if (exists $selector_ref->{$selection}) {
    100          
48 2         3 $handler = $selector_ref->{$selection};
49 2         3 last SELECTION;
50             }
51             elsif ($flag) {
52 1         6 die _in_context "Invalid option: $flag => $selection";
53             }
54             }
55              
56             # (Re)set handler...
57 3 50       7 if ($handler) {
58 3         14 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         834 $handler_for{$caller_loc} = $handler;
63             }
64             };
65              
66             sub _FAIL (;&) {
67             # Generate args...
68 20     20   1286 my $arg_generator_ref = shift;
69 20         18 my @args;
70 20 100       34 if ($arg_generator_ref) {
71             package DB;
72 5         17 ()=CORE::caller(1);
73 5         11 @args = $arg_generator_ref->(@DB::args);
74             }
75              
76             # Handle user-defined failure semantics...
77 20         75 my $caller_loc = join '|', (CORE::caller 1)[0,1];
78 20 100       45 if (exists $handler_for{$caller_loc} ) {
79             # Fake out caller() and Carp...
80 10         9 local $Contextual::Return::uplevel = 1;
81              
82 10         21 return $handler_for{$caller_loc}->(@args);
83             }
84              
85 10 50       29 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       19 if (!ref $exception) {
92 10         23 $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   3 BOOL { 0 }
103             DEFAULT {
104 8 50   8   11 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         14 die _in_context $exception, "Attempted to use failure value";
111             }
112             }
113             METHOD {
114 1         5 error => sub { _in_context $exception }
115 1     1   7 }
116 10         57 }
117              
118             1;
119              
120             __END__