File Coverage

blib/lib/Class/ReturnValue.pm
Criterion Covered Total %
statement 72 82 87.8
branch 14 20 70.0
condition n/a
subroutine 20 21 95.2
pod 7 9 77.7
total 113 132 85.6


line stmt bran cond sub pod time code
1 1     1   827 use warnings;
  1         2  
  1         35  
2 1     1   5 use strict;
  1         2  
  1         52  
3              
4             package Class::ReturnValue;
5              
6              
7             =head1 NAME
8              
9             Class::ReturnValue - A return-value object that lets you treat it
10             as as a boolean, array or object
11              
12             =head1 DESCRIPTION
13              
14             Class::ReturnValue is a "clever" return value object that can allow
15             code calling your routine to expect:
16             a boolean value (did it fail)
17             or a list (what are the return values)
18              
19             =head1 EXAMPLE
20              
21             sub demo {
22             my $value = shift;
23             my $ret = Class::ReturnValue->new();
24             $ret->as_array('0', 'No results found');
25            
26             unless($value) {
27             $ret->as_error(errno => '1',
28             message => "You didn't supply a parameter.",
29             do_backtrace => 1);
30             }
31              
32             return($ret->return_value);
33             }
34              
35             if (demo('foo')){
36             print "the routine succeeded with one parameter";
37             }
38             if (demo()) {
39             print "The routine succeeded with 0 paramters. shouldn't happen";
40             } else {
41             print "The routine failed with 0 parameters (as it should).";
42             }
43              
44              
45             my $return = demo();
46             if ($return) {
47             print "The routine succeeded with 0 paramters. shouldn't happen";
48             } else {
49             print "The routine failed with 0 parameters (as it should). ".
50             "Stack trace:\n".
51             $return->backtrace;
52             }
53              
54             my @return3 = demo('foo');
55             print "The routine got ".join(',',@return3).
56             "when asking for demo's results as an array";
57              
58              
59             my $return2 = demo('foo');
60              
61             unless ($return2) {
62             print "The routine failed with a parameter. shouldn't happen.".
63             "Stack trace:\n".
64             $return2->backtrace;
65             }
66              
67             my @return2_array = @{$return2}; # TODO: does this work
68             my @return2_array2 = $return2->as_array;
69              
70              
71             =cut
72              
73              
74 1     1   20 use Exporter;
  1         2  
  1         51  
75              
76 1     1   5 use vars qw/$VERSION @EXPORT @ISA/;
  1         1  
  1         92  
77              
78             @ISA = qw/Exporter/;
79             @EXPORT = qw /&return_value/;
80 1     1   5 use Carp;
  1         2  
  1         61  
81 1     1   949 use Devel::StackTrace;
  1         4449  
  1         29  
82 1     1   2211 use Data::Dumper;
  1         7191  
  1         107  
83              
84              
85             $VERSION = '0.55';
86              
87              
88 1     1   10 use overload 'bool' => \&error_condition;
  1         2  
  1         13  
89 1     1   63 use overload '""' => \&error_condition;
  1         2  
  1         4  
90 1     1   47 use overload 'eq' => \&my_eq;
  1         2  
  1         6  
91 1     1   47 use overload '@{}' => \&as_array;
  1         2  
  1         6  
92 1     1   47 use overload 'fallback' => \&as_array;
  1         2  
  1         4  
93              
94              
95             =head1 METHODS
96              
97             =item new
98              
99             Instantiate a new Class::ReturnValue object
100              
101             =cut
102              
103             sub new {
104 11     11 1 4655 my $self = {};
105 11         15 bless($self);
106 11         30 return($self);
107             }
108              
109             sub my_eq {
110 0     0 0 0 my $self = shift;
111 0 0       0 if (wantarray()) {
112 0         0 return($self->as_array);
113             }
114             else {
115 0         0 return($self);
116             }
117             }
118              
119             =item as_array
120              
121             Return the 'as_array' attribute of this object as an array.
122              
123             =cut
124              
125              
126             =item as_array [ARRAY]
127              
128             If $self is called in an array context, returns the array specified in ARRAY
129              
130             =cut
131              
132             sub as_array {
133              
134 10     10 1 30 my $self = shift;
135 10 100       27 if (@_) {
136 6         764 @{$self->{'as_array'}} = (@_);
  6         89  
137             }
138 10         17 return(@{$self->{'as_array'}});
  10         793  
139             }
140              
141              
142             =item as_error HASH
143              
144             Turns this return-value object into an error return object. TAkes three parameters:
145              
146             message
147             do_backtrace
148             errno
149              
150             'message' is a human readable error message explaining what's going on
151              
152             'do_backtrace' is a boolean. If it's true, a carp-style backtrace will be
153             stored in $self->{'backtrace'}. It defaults to true
154              
155             errno and message default to undef. errno _must_ be specified.
156             It's a numeric error number. Any true integer value will cause the
157             object to evaluate to false in a scalar context. At first, this may look a
158             bit counterintuitive, but it means that you can have error codes and still
159             allow simple use of your functions in a style like this:
160              
161              
162             if ($obj->do_something) {
163             print "Yay! it worked";
164             } else {
165             print "Sorry. there's been an error.";
166             }
167              
168              
169             as well as more complex use like this:
170              
171             my $retval = $obj->do_something;
172            
173             if ($retval) {
174             print "Yay. we did something\n";
175             my ($foo, $bar, $baz) = @{$retval};
176             my $human_readable_return = $retval;
177             } else {
178             if ($retval->errno == 20) {
179             die "Failed with error 20 (Not enough monkeys).";
180             } else {
181             die $retval->backtrace; # Die and print out a backtrace
182             }
183             }
184            
185              
186             =cut
187              
188             sub as_error {
189 3     3 1 9 my $self = shift;
190 3         26 my %args = ( errno => undef,
191             message => undef,
192             do_backtrace => 1,
193             @_);
194              
195 3 50       14 unless($args{'errno'}) {
196 0         0 carp "$self -> as_error called without an 'errno' parameter";
197 0         0 return (undef);
198             }
199              
200 3         10 $self->{'errno'} = $args{'errno'};
201 3         185 $self->{'error_message'} = $args{'message'};
202 3 100       11 if ($args{'do_backtrace'}) {
203             # Use carp's internal backtrace methods, rather than duplicating them ourselves
204 2         16 my $trace = Devel::StackTrace->new(ignore_package => 'Class::ReturnValue');
205              
206 2         215 $self->{'backtrace'} = $trace->as_string; # like carp
207             }
208              
209 3         673 return(1);
210             }
211              
212              
213             =item errno
214              
215             Returns the errno if there's been an error. Otherwise, return undef
216              
217             =cut
218              
219             sub errno {
220 2     2 1 4 my $self = shift;
221 2 50       9 if ($self->{'errno'}) {
222 2         10 return ($self->{'errno'});
223             }
224             else {
225 0         0 return(undef);
226             }
227             }
228              
229              
230             =item error_message
231              
232             If there's been an error return the error message.
233              
234             =cut
235              
236             sub error_message {
237 1     1 1 3 my $self = shift;
238 1 50       6 if ($self->{'error_message'}) {
239 1         7 return($self->{'error_message'});
240             }
241             else {
242 0         0 return(undef);
243             }
244             }
245              
246              
247             =item backtrace
248              
249             If there's been an error and we asked for a backtrace, return the backtrace.
250             Otherwise, return undef.
251              
252             =cut
253              
254             sub backtrace {
255 2     2 1 6 my $self = shift;
256 2 100       14 if ($self->{'backtrace'}) {
257 1         12 return($self->{'backtrace'});
258             }
259             else {
260 1         4 return(undef);
261             }
262             }
263              
264             =cut
265              
266             =item error_condition
267              
268             If there's been an error, return undef. Otherwise return 1
269              
270             =cut
271              
272             sub error_condition {
273 9     9 1 106 my $self = shift;
274 9 100       31 if ($self->{'errno'}) {
    50          
275 2         7 return (undef);
276             }
277             elsif (wantarray()) {
278 0         0 return(@{$self->{'as_array'}});
  0         0  
279             }
280             else {
281 7         20 return(1);
282             }
283             }
284              
285             sub return_value {
286 9     9 0 33 my $self = shift;
287 9 100       20 if (wantarray) {
288 3         7 return ($self->as_array);
289             }
290             else {
291 6         27 return ($self);
292             }
293             }
294              
295              
296             =head1 AUTHOR
297            
298             Jesse Vincent
299              
300             =head1 BUGS
301              
302             This module has, as yet, not been used in production code. I thing
303             it should work, but have never benchmarked it. I have not yet used
304             it extensively, though I do plan to in the not-too-distant future.
305             If you have questions or comments, please write me.
306              
307             If you need to report a bug, please send mail to
308             or report your error on the web
309             at http://rt.cpan.org/
310              
311             =head1 COPYRIGHT
312              
313             Copyright (c) 2002,2003,2005,2007 Jesse Vincent
314             You may use, modify, fold, spindle or mutilate this module under
315             the same terms as perl itself.
316              
317             =head1 SEE ALSO
318              
319             Class::ReturnValue isn't an exception handler. If it doesn't
320             do what you want, you might want look at one of the exception handlers
321             below:
322              
323             Error, Exception, Exceptions, Exceptions::Class
324              
325             You might also want to look at Contextual::Return, another implementation
326             of the same concept as this module.
327              
328             =cut
329              
330             1;