File Coverage

blib/lib/Return/Value.pm
Criterion Covered Total %
statement 63 63 100.0
branch 28 28 100.0
condition 3 3 100.0
subroutine 30 30 100.0
pod 6 6 100.0
total 130 130 100.0


line stmt bran cond sub pod time code
1 4     4   91847 use strict;
  4         9  
  4         107  
2 4     4   20 use warnings;
  4         7  
  4         223  
3             package Return::Value;
4             # ABSTRACT: (deprecated) polymorphic return values
5             # vi:et:sw=4 ts=4
6             $Return::Value::VERSION = '1.666005';
7 4     4   19 use Exporter 5.57 'import';
  4         95  
  4         163  
8 4     4   23 use Carp ();
  4         7  
  4         2361  
9              
10             our @EXPORT = qw[success failure];
11              
12             #pod =head1 DO NOT USE THIS LIBRARY
13             #pod
14             #pod Return::Value was a bad idea. I'm sorry that I had it, sorry that I followed
15             #pod through, and sorry that it got used in other useful libraries. Fortunately
16             #pod there are not many things using it. One of those things is
17             #pod L which is also deprecated in favor of
18             #pod L.
19             #pod
20             #pod There's no reason to specify a new module to replace Return::Value. In
21             #pod general, routines should return values of uniform type or throw exceptions.
22             #pod Return::Value tried to be a uniform type for all routines, but has so much
23             #pod weird behavior that it ends up being confusing and not very Perl-like.
24             #pod
25             #pod Objects that are false are just a dreadful idea in almost every circumstance,
26             #pod especially when the object has useful properties.
27             #pod
28             #pod B
29             #pod
30             #pod A release of this library in June 2009 promised that deprecation warnings would
31             #pod start being issued in June 2010. It is now December 2012, and the warnings are
32             #pod now being issued. They can be disabled through means made clear from the
33             #pod source.
34             #pod
35             #pod =head1 SYNOPSIS
36             #pod
37             #pod Used with basic function-call interface:
38             #pod
39             #pod use Return::Value;
40             #pod
41             #pod sub send_over_network {
42             #pod my ($net, $send) = @_:
43             #pod if ( $net->transport( $send ) ) {
44             #pod return success;
45             #pod } else {
46             #pod return failure "Was not able to transport info.";
47             #pod }
48             #pod }
49             #pod
50             #pod my $result = $net->send_over_network( "Data" );
51             #pod
52             #pod # boolean
53             #pod unless ( $result ) {
54             #pod # string
55             #pod print $result;
56             #pod }
57             #pod
58             #pod Or, build your Return::Value as an object:
59             #pod
60             #pod sub build_up_return {
61             #pod my $return = failure;
62             #pod
63             #pod if ( ! foo() ) {
64             #pod $return->string("Can't foo!");
65             #pod return $return;
66             #pod }
67             #pod
68             #pod if ( ! bar() ) {
69             #pod $return->string("Can't bar");
70             #pod $return->prop(failures => \@bars);
71             #pod return $return;
72             #pod }
73             #pod
74             #pod # we're okay if we made it this far.
75             #pod $return++;
76             #pod return $return; # success!
77             #pod }
78             #pod
79             #pod =head1 DESCRIPTION
80             #pod
81             #pod Polymorphic return values are a horrible idea, but this library was written
82             #pod based on the notion that they were useful. Often, we just want to know if
83             #pod something worked or not. Other times, we'd like to know what the error text
84             #pod was. Still others, we may want to know what the error code was, and what the
85             #pod error properties were. We don't want to handle objects or data structures for
86             #pod every single return value, but we do want to check error conditions in our code
87             #pod because that's what good programmers do.
88             #pod
89             #pod When functions are successful they may return true, or perhaps some useful
90             #pod data. In the quest to provide consistent return values, this gets confusing
91             #pod between complex, informational errors and successful return values.
92             #pod
93             #pod This module provides these features with a simplistic API that should get you
94             #pod what you're looking for in each context a return value is used in.
95             #pod
96             #pod =head2 Attributes
97             #pod
98             #pod All return values have a set of attributes that package up the information
99             #pod returned. All attributes can be accessed or changed via methods of the same
100             #pod name, unless otherwise noted. Many can also be accessed via overloaded
101             #pod operations on the object, as noted below.
102             #pod
103             #pod =over 4
104             #pod
105             #pod =item type
106             #pod
107             #pod A value's type is either "success" or "failure" and (obviously) reflects
108             #pod whether the value is returning success or failure.
109             #pod
110             #pod =item errno
111             #pod
112             #pod The errno attribute stores the error number of the return value. For
113             #pod success-type results, it is by default undefined. For other results, it
114             #pod defaults to 1.
115             #pod
116             #pod =item string
117             #pod
118             #pod The value's string attribute is a simple message describing the value.
119             #pod
120             #pod =item data
121             #pod
122             #pod The data attribute stores a reference to a hash or array, and can be used as a
123             #pod simple way to return extra data. Data stored in the data attribute can be
124             #pod accessed by dereferencing the return value itself. (See below.)
125             #pod
126             #pod =item prop
127             #pod
128             #pod The most generic attribute of all, prop is a hashref that can be used to pass
129             #pod an arbitrary number of data structures, just like the data attribute. Unlike
130             #pod the data attribute, though, these structures must be retrieved via method calls.
131             #pod
132             #pod =back
133             #pod
134             #pod =head1 FUNCTIONS
135             #pod
136             #pod The functional interface is highly recommended for use within functions
137             #pod that are using C for return values. It's simple and
138             #pod straightforward, and builds the entire return value in one statement.
139             #pod
140             #pod =over 4
141             #pod
142             #pod =cut
143              
144             # This hack probably impacts performance more than I'd like to know, but it's
145             # needed to have a hashref object that can deref into a different hash.
146             # _ah($self,$key, [$value) sets or returns the value for the given key on the
147             # $self blessed-ref
148              
149             sub _ah {
150 95     95   162 my ($self, $key, $value) = @_;
151 95         152 my $class = ref $self;
152 95         196 bless $self => "ain't::overloaded";
153 95 100       217 $self->{$key} = $value if @_ > 2;
154 95         186 my $return = $self->{$key};
155 95         174 bless $self => $class;
156 95         600 return $return;
157             }
158              
159             sub _builder {
160 23     23   67 my %args = (type => shift);
161 23 100       83 $args{string} = shift if (@_ % 2);
162 23         94 %args = (%args, @_);
163              
164 23 100       82 $args{string} = $args{type} unless defined $args{string};
165              
166             $args{errno} = ($args{type} eq 'success' ? undef : 1)
167 23 100       94 unless defined $args{errno};
    100          
168              
169 23         98 __PACKAGE__->new(%args);
170             }
171              
172             #pod =item success
173             #pod
174             #pod The C function returns a C with the type "success".
175             #pod
176             #pod Additional named parameters may be passed to set the returned object's
177             #pod attributes. The first, optional, parameter is the string attribute and does
178             #pod not need to be named. All other parameters must be passed by name.
179             #pod
180             #pod # simplest possible case
181             #pod return success;
182             #pod
183             #pod =cut
184              
185 10     10 1 1826 sub success { _builder('success', @_) }
186              
187             #pod =pod
188             #pod
189             #pod =item failure
190             #pod
191             #pod C is identical to C, but returns an object with the type
192             #pod "failure"
193             #pod
194             #pod =cut
195              
196 13     13 1 2284 sub failure { _builder('failure', @_) }
197              
198             #pod =pod
199             #pod
200             #pod =back
201             #pod
202             #pod =head1 METHODS
203             #pod
204             #pod The object API is useful in code that is catching C objects.
205             #pod
206             #pod =over 4
207             #pod
208             #pod =item new
209             #pod
210             #pod my $return = Return::Value->new(
211             #pod type => 'failure',
212             #pod string => "YOU FAIL",
213             #pod prop => {
214             #pod failed_objects => \@objects,
215             #pod },
216             #pod );
217             #pod
218             #pod Creates a new C object. Named parameters can be used to set the
219             #pod object's attributes.
220             #pod
221             #pod =cut
222              
223             sub new {
224 25     25 1 56 my $class = shift;
225 25         177 bless { type => 'failure', string => q{}, prop => {}, @_ } => $class;
226             }
227              
228             #pod =pod
229             #pod
230             #pod =item bool
231             #pod
232             #pod print "it worked" if $result->bool;
233             #pod
234             #pod Returns the result in boolean context: true for success, false for failure.
235             #pod
236             #pod =item prop
237             #pod
238             #pod printf "%s: %s',
239             #pod $result->string, join ' ', @{$result->prop('strings')}
240             #pod unless $result->bool;
241             #pod
242             #pod Returns the return value's properties. Accepts the name of
243             #pod a property returned, or returns the properties hash reference
244             #pod if given no name.
245             #pod
246             #pod =item other attribute accessors
247             #pod
248             #pod Simple accessors exist for the object's other attributes: C, C,
249             #pod C, and C.
250             #pod
251             #pod =cut
252              
253 30 100   30 1 891 sub bool { _ah($_[0],'type') eq 'success' ? 1 : 0 }
254              
255             sub type {
256 4     4 1 9 my ($self, $value) = @_;
257 4 100       18 return _ah($self, 'type') unless @_ > 1;
258 3 100 100     174 Carp::croak "invalid result type: $value"
259             unless $value eq 'success' or $value eq 'failure';
260 2         22 return _ah($self, 'type', $value);
261             };
262              
263             foreach my $name ( qw[errno string data] ) {
264             ## no critic (ProhibitNoStrict)
265 4     4   23 no strict 'refs';
  4         19  
  4         2522  
266             *{$name} = sub {
267 40     40   69 my ($self, $value) = @_;
268 40 100       149 return _ah($self, $name) unless @_ > 1;
269 2         5 return _ah($self, $name, $value);
270             };
271             }
272              
273             sub prop {
274 5     5 1 7 my ($self, $name, $value) = @_;
275 5 100       19 return _ah($self, 'prop') unless $name;
276 2 100       7 return _ah($self, 'prop')->{$name} unless @_ > 2;
277 1         3 return _ah($self, 'prop')->{$name} = $value;
278             }
279              
280             #pod =pod
281             #pod
282             #pod =back
283             #pod
284             #pod =head2 Overloading
285             #pod
286             #pod Several operators are overloaded for C objects. They are
287             #pod listed here.
288             #pod
289             #pod =over 4
290             #pod
291             #pod =item Stringification
292             #pod
293             #pod print "$result\n";
294             #pod
295             #pod Stringifies to the string attribute.
296             #pod
297             #pod =item Boolean
298             #pod
299             #pod print $result unless $result;
300             #pod
301             #pod Returns the C representation.
302             #pod
303             #pod =item Numeric
304             #pod
305             #pod Also returns the C value.
306             #pod
307             #pod =item Dereference
308             #pod
309             #pod Dereferencing the value as a hash or array will return the value of the data
310             #pod attribute, if it matches that type, or an empty reference otherwise. You can
311             #pod check C<< ref $result->data >> to determine what kind of data (if any) was
312             #pod passed.
313             #pod
314             #pod =cut
315              
316             use overload
317 1     1   4 '""' => sub { shift->string },
318 13     13   4293 'bool' => sub { shift->bool },
319 11     11   1939 '==' => sub { shift->bool == shift },
320 1     1   84 '!=' => sub { shift->bool != shift },
321 1     1   3 '>' => sub { shift->bool > shift },
322 1     1   4 '<' => sub { shift->bool < shift },
323 11     11   119 'eq' => sub { shift->string eq shift },
324 2     2   465 'ne' => sub { shift->string ne shift },
325 2     2   460 'gt' => sub { shift->string gt shift },
326 2     2   454 'lt' => sub { shift->string lt shift },
327 1     1   8 '++' => sub { _ah(shift,'type','success') },
328 1     1   406 '--' => sub { _ah(shift,'type','failure') },
329 3 100   3   426 '${}' => sub { my $data = _ah($_[0],'data'); $data ? \$data : \undef },
  3         22  
330 3 100   3   10 '%{}' => sub { ref _ah($_[0],'data') eq 'HASH' ? _ah($_[0],'data') : {} },
331 4 100   4   15 '@{}' => sub { ref _ah($_[0],'data') eq 'ARRAY' ? _ah($_[0],'data') : [] },
332 4     4   6910 fallback => 1;
  4         4894  
  4         185  
333              
334             #pod =pod
335             #pod
336             #pod =back
337             #pod
338             #pod =cut
339              
340             "This return value is true.";
341              
342             __END__