|
Packit |
c9e8cb |
use warnings;
|
|
Packit |
c9e8cb |
use strict;
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
package Class::ReturnValue;
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=head1 NAME
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
Class::ReturnValue - A return-value object that lets you treat it
|
|
Packit |
c9e8cb |
as as a boolean, array or object
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=head1 DESCRIPTION
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
Class::ReturnValue is a "clever" return value object that can allow
|
|
Packit |
c9e8cb |
code calling your routine to expect:
|
|
Packit |
c9e8cb |
a boolean value (did it fail)
|
|
Packit |
c9e8cb |
or a list (what are the return values)
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=head1 EXAMPLE
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
sub demo {
|
|
Packit |
c9e8cb |
my $value = shift;
|
|
Packit |
c9e8cb |
my $ret = Class::ReturnValue->new();
|
|
Packit |
c9e8cb |
$ret->as_array('0', 'No results found');
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
unless($value) {
|
|
Packit |
c9e8cb |
$ret->as_error(errno => '1',
|
|
Packit |
c9e8cb |
message => "You didn't supply a parameter.",
|
|
Packit |
c9e8cb |
do_backtrace => 1);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
return($ret->return_value);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
if (demo('foo')){
|
|
Packit |
c9e8cb |
print "the routine succeeded with one parameter";
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
if (demo()) {
|
|
Packit |
c9e8cb |
print "The routine succeeded with 0 paramters. shouldn't happen";
|
|
Packit |
c9e8cb |
} else {
|
|
Packit |
c9e8cb |
print "The routine failed with 0 parameters (as it should).";
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
my $return = demo();
|
|
Packit |
c9e8cb |
if ($return) {
|
|
Packit |
c9e8cb |
print "The routine succeeded with 0 paramters. shouldn't happen";
|
|
Packit |
c9e8cb |
} else {
|
|
Packit |
c9e8cb |
print "The routine failed with 0 parameters (as it should). ".
|
|
Packit |
c9e8cb |
"Stack trace:\n".
|
|
Packit |
c9e8cb |
$return->backtrace;
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
my @return3 = demo('foo');
|
|
Packit |
c9e8cb |
print "The routine got ".join(',',@return3).
|
|
Packit |
c9e8cb |
"when asking for demo's results as an array";
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
my $return2 = demo('foo');
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
unless ($return2) {
|
|
Packit |
c9e8cb |
print "The routine failed with a parameter. shouldn't happen.".
|
|
Packit |
c9e8cb |
"Stack trace:\n".
|
|
Packit |
c9e8cb |
$return2->backtrace;
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
my @return2_array = @{$return2}; # TODO: does this work
|
|
Packit |
c9e8cb |
my @return2_array2 = $return2->as_array;
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
use Exporter;
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
use vars qw/$VERSION @EXPORT @ISA/;
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
@ISA = qw/Exporter/;
|
|
Packit |
c9e8cb |
@EXPORT = qw /&return_value/;
|
|
Packit |
c9e8cb |
use Carp;
|
|
Packit |
c9e8cb |
use Devel::StackTrace;
|
|
Packit |
c9e8cb |
use Data::Dumper;
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
$VERSION = '0.55';
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
use overload 'bool' => \&error_condition;
|
|
Packit |
c9e8cb |
use overload '""' => \&error_condition;
|
|
Packit |
c9e8cb |
use overload 'eq' => \&my_eq;
|
|
Packit |
c9e8cb |
use overload '@{}' => \&as_array;
|
|
Packit |
c9e8cb |
use overload 'fallback' => \&as_array;
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=head1 METHODS
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=item new
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
Instantiate a new Class::ReturnValue object
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
sub new {
|
|
Packit |
c9e8cb |
my $self = {};
|
|
Packit |
c9e8cb |
bless($self);
|
|
Packit |
c9e8cb |
return($self);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
sub my_eq {
|
|
Packit |
c9e8cb |
my $self = shift;
|
|
Packit |
c9e8cb |
if (wantarray()) {
|
|
Packit |
c9e8cb |
return($self->as_array);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
else {
|
|
Packit |
c9e8cb |
return($self);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=item as_array
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
Return the 'as_array' attribute of this object as an array.
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=item as_array [ARRAY]
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
If $self is called in an array context, returns the array specified in ARRAY
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
sub as_array {
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
my $self = shift;
|
|
Packit |
c9e8cb |
if (@_) {
|
|
Packit |
c9e8cb |
@{$self->{'as_array'}} = (@_);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
return(@{$self->{'as_array'}});
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=item as_error HASH
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
Turns this return-value object into an error return object. TAkes three parameters:
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
message
|
|
Packit |
c9e8cb |
do_backtrace
|
|
Packit |
c9e8cb |
errno
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
'message' is a human readable error message explaining what's going on
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
'do_backtrace' is a boolean. If it's true, a carp-style backtrace will be
|
|
Packit |
c9e8cb |
stored in $self->{'backtrace'}. It defaults to true
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
errno and message default to undef. errno _must_ be specified.
|
|
Packit |
c9e8cb |
It's a numeric error number. Any true integer value will cause the
|
|
Packit |
c9e8cb |
object to evaluate to false in a scalar context. At first, this may look a
|
|
Packit |
c9e8cb |
bit counterintuitive, but it means that you can have error codes and still
|
|
Packit |
c9e8cb |
allow simple use of your functions in a style like this:
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
if ($obj->do_something) {
|
|
Packit |
c9e8cb |
print "Yay! it worked";
|
|
Packit |
c9e8cb |
} else {
|
|
Packit |
c9e8cb |
print "Sorry. there's been an error.";
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
as well as more complex use like this:
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
my $retval = $obj->do_something;
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
if ($retval) {
|
|
Packit |
c9e8cb |
print "Yay. we did something\n";
|
|
Packit |
c9e8cb |
my ($foo, $bar, $baz) = @{$retval};
|
|
Packit |
c9e8cb |
my $human_readable_return = $retval;
|
|
Packit |
c9e8cb |
} else {
|
|
Packit |
c9e8cb |
if ($retval->errno == 20) {
|
|
Packit |
c9e8cb |
die "Failed with error 20 (Not enough monkeys).";
|
|
Packit |
c9e8cb |
} else {
|
|
Packit |
c9e8cb |
die $retval->backtrace; # Die and print out a backtrace
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
sub as_error {
|
|
Packit |
c9e8cb |
my $self = shift;
|
|
Packit |
c9e8cb |
my %args = ( errno => undef,
|
|
Packit |
c9e8cb |
message => undef,
|
|
Packit |
c9e8cb |
do_backtrace => 1,
|
|
Packit |
c9e8cb |
@_);
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
unless($args{'errno'}) {
|
|
Packit |
c9e8cb |
carp "$self -> as_error called without an 'errno' parameter";
|
|
Packit |
c9e8cb |
return (undef);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
$self->{'errno'} = $args{'errno'};
|
|
Packit |
c9e8cb |
$self->{'error_message'} = $args{'message'};
|
|
Packit |
c9e8cb |
if ($args{'do_backtrace'}) {
|
|
Packit |
c9e8cb |
# Use carp's internal backtrace methods, rather than duplicating them ourselves
|
|
Packit |
c9e8cb |
my $trace = Devel::StackTrace->new(ignore_package => 'Class::ReturnValue');
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
$self->{'backtrace'} = $trace->as_string; # like carp
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
return(1);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=item errno
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
Returns the errno if there's been an error. Otherwise, return undef
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
sub errno {
|
|
Packit |
c9e8cb |
my $self = shift;
|
|
Packit |
c9e8cb |
if ($self->{'errno'}) {
|
|
Packit |
c9e8cb |
return ($self->{'errno'});
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
else {
|
|
Packit |
c9e8cb |
return(undef);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=item error_message
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
If there's been an error return the error message.
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
sub error_message {
|
|
Packit |
c9e8cb |
my $self = shift;
|
|
Packit |
c9e8cb |
if ($self->{'error_message'}) {
|
|
Packit |
c9e8cb |
return($self->{'error_message'});
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
else {
|
|
Packit |
c9e8cb |
return(undef);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=item backtrace
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
If there's been an error and we asked for a backtrace, return the backtrace.
|
|
Packit |
c9e8cb |
Otherwise, return undef.
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
sub backtrace {
|
|
Packit |
c9e8cb |
my $self = shift;
|
|
Packit |
c9e8cb |
if ($self->{'backtrace'}) {
|
|
Packit |
c9e8cb |
return($self->{'backtrace'});
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
else {
|
|
Packit |
c9e8cb |
return(undef);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=item error_condition
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
If there's been an error, return undef. Otherwise return 1
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
sub error_condition {
|
|
Packit |
c9e8cb |
my $self = shift;
|
|
Packit |
c9e8cb |
if ($self->{'errno'}) {
|
|
Packit |
c9e8cb |
return (undef);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
elsif (wantarray()) {
|
|
Packit |
c9e8cb |
return(@{$self->{'as_array'}});
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
else {
|
|
Packit |
c9e8cb |
return(1);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
sub return_value {
|
|
Packit |
c9e8cb |
my $self = shift;
|
|
Packit |
c9e8cb |
if (wantarray) {
|
|
Packit |
c9e8cb |
return ($self->as_array);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
else {
|
|
Packit |
c9e8cb |
return ($self);
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
}
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=head1 AUTHOR
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
Jesse Vincent <jesse@bestpractical.com>
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=head1 BUGS
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
This module has, as yet, not been used in production code. I thing
|
|
Packit |
c9e8cb |
it should work, but have never benchmarked it. I have not yet used
|
|
Packit |
c9e8cb |
it extensively, though I do plan to in the not-too-distant future.
|
|
Packit |
c9e8cb |
If you have questions or comments, please write me.
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
If you need to report a bug, please send mail to
|
|
Packit |
c9e8cb |
<bug-class-returnvalue@rt.cpan.org> or report your error on the web
|
|
Packit |
c9e8cb |
at http://rt.cpan.org/
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=head1 COPYRIGHT
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
Copyright (c) 2002,2003,2005,2007 Jesse Vincent <jesse@bestpractical.com>
|
|
Packit |
c9e8cb |
You may use, modify, fold, spindle or mutilate this module under
|
|
Packit |
c9e8cb |
the same terms as perl itself.
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=head1 SEE ALSO
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
Class::ReturnValue isn't an exception handler. If it doesn't
|
|
Packit |
c9e8cb |
do what you want, you might want look at one of the exception handlers
|
|
Packit |
c9e8cb |
below:
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
Error, Exception, Exceptions, Exceptions::Class
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
You might also want to look at Contextual::Return, another implementation
|
|
Packit |
c9e8cb |
of the same concept as this module.
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
=cut
|
|
Packit |
c9e8cb |
|
|
Packit |
c9e8cb |
1;
|