File Coverage

blib/lib/Call/Context.pm
Criterion Covered Total %
statement 24 24 100.0
branch 8 8 100.0
condition 2 3 66.6
subroutine 8 8 100.0
pod 2 2 100.0
total 44 45 97.7


line stmt bran cond sub pod time code
1             package Call::Context;
2              
3             =encoding utf-8
4              
5             =head1 NAME
6              
7             Call::Context - Sanity-check calling context
8              
9             =head1 SYNOPSIS
10              
11             use Call::Context;
12              
13             sub gives_a_list {
14              
15             #Will die() if the context is not list.
16             Call::Context::must_be_list();
17              
18             return (1, 2, 3);
19             }
20              
21             gives_a_list(); # die()s: incorrect context (void)
22              
23             my $v = gives_a_list(); # die()s: incorrect context (scalar)
24              
25             my @list = gives_a_list(); # lives
26              
27             #----------------------------------------------------------------------
28              
29             sub scalar_is_bad {
30              
31             #Will die() if the context is not list.
32             Call::Context::must_not_be_scalar();
33              
34             return (1, 2, 3);
35             }
36              
37             scalar_is_bad(); # lives
38              
39             my $v = scalar_is_bad(); # die()s: incorrect context (scalar)
40              
41             my @list = scalar_is_bad(); # lives
42              
43             =head1 DISCUSSION
44              
45             If your function only expects to return a list, then a call in some other
46             context is, by definition, an error. The problem is that, depending on how
47             the function is written, it may actually do something expected in testing, but
48             then in production act differently.
49              
50             =head1 FUNCTIONS
51              
52             =head2 must_be_list()
53              
54             Cs if the calling function is itself called outside list context.
55             (See the SYNOPSIS for examples.)
56              
57             =head2 must_not_be_scalar()
58              
59             Cs if the calling function is itself called in scalar context.
60             (See the SYNOPSIS for examples.)
61              
62             =head1 EXCEPTIONS
63              
64             This module throws instances of C. C is
65             overloaded to stringify; however, to keep memory usage low, C is not
66             loaded until instantiation.
67              
68             =head1 REPOSITORY
69              
70             https://github.com/FGasper/p5-Call-Context
71              
72             =cut
73              
74 3     3   208702 use strict;
  3         29  
  3         96  
75 3     3   19 use warnings;
  3         9  
  3         1066  
76              
77             our $VERSION = '0.03-TRIAL1';
78              
79             my $_OVERLOADED_X;
80              
81             our $_ACCEPT_VOID;
82              
83             sub must_be_list {
84 3     3 1 834 return _must_be_list(0);
85             }
86              
87             sub must_not_be_scalar {
88 3 100   3 1 1590 return if !defined( (caller 1)[5] );
89 2         9 return _must_be_list(1);
90             }
91              
92             sub _must_be_list {
93 5 100   5   39 return if (caller(1 + $_[0]))[5]; #wantarray
94              
95 3   66 2   202 $_OVERLOADED_X ||= eval q{
  2         17  
  2         4  
  2         13  
96             package Call::Context::X;
97             use overload ( q<""> => \\&_spew );
98             1;
99             };
100              
101 3         12 die Call::Context::X->_new($_[0]);
102             }
103              
104             #----------------------------------------------------------------------
105              
106             package Call::Context::X;
107              
108             #Not to be instantiated except from Call::Context!
109              
110             sub _new {
111 3     3   8 my ($class, $accept_void_yn) = @_;
112              
113 3         22 my ($sub, $ctx) = (caller 3)[3, 5];
114 3         15 my (undef, $cfilename, $cline, $csub) = caller 4;
115              
116 3 100       13 if ($accept_void_yn) {
117 1         13 return bless \"$sub called in scalar context from $csub (line $cline of $cfilename)", $class;
118             }
119              
120 2 100       6 $ctx = defined($ctx) ? 'scalar' : 'void';
121              
122 2         19 return bless \"$sub called in non-list ($ctx) context from $csub (line $cline of $cfilename)", $class;
123             }
124              
125 7     7   999 sub _spew { ${ $_[0] } }
  7         128  
126              
127             1;