/usr/local/CPAN/Callback/Callback.pm
package Callback;
require Exporter;
require UNIVERSAL;
$VERSION = $VERSION = 1.07;
@ISA = (Exporter);
@EXPORT_OK = qw(@callbackTrace);
use strict;
sub new
{
my ($package,$func,@args) = @_;
my ($p, $file, $line) = caller(0);
my @method;
if (ref $func ne 'CODE' && UNIVERSAL::isa($func, "UNIVERSAL")) {
if ($func->isa('Callback')) {
return $func unless @args;
my $new = bless { %$func }, $package;
push(@{$new->{ARGS}}, @args);
return $new;
} else {
my $method = shift @args;
my $obj = $func;
$func = $obj->can($method);
unless (defined $func) {
require Carp;
Carp::croak("Can't locate method '$method' for object $obj");
}
unshift(@args, $obj);
@method = (METHOD => $method); # For Storable hooks
}
}
my $x = {
FUNC => $func,
ARGS => [@args],
CALLER => "$file:$line",
@method
};
return bless $x, $package;
}
sub call
{
my ($this, @args) = @_;
my ($ret, @ret);
unshift(@Callback::callbackTrace, $this->{CALLER});
if (wantarray) {
@ret = eval {&{$this->{FUNC}}(@{$this->{ARGS}},@args)};
} else {
$ret = eval {&{$this->{FUNC}}(@{$this->{ARGS}},@args)};
}
shift(@Callback::callbackTrace);
die $@ if $@;
return @ret if wantarray;
return $ret;
}
sub DELETE
{
}
#
# Storable hooks
#
# We cannot serialize something containing a pure CODE ref, which is the
# case if there's no METHOD attribute in the object.
#
# However, when Callback is a method call, we can remove the FUNC attribute
# and serialize the object: the function address will be recomputed at
# retrieve time.
#
sub STORABLE_freeze {
my ($self, $cloning) = @_;
return if $cloning;
my %copy = %$self;
die "cannot store $self since it contains CODE references\n"
unless exists $copy{METHOD};
delete $copy{FUNC};
return ("", \%copy);
}
sub STORABLE_thaw {
my ($self, $cloning, $x, $copy) = @_;
%$self = %$copy;
my $method = $self->{METHOD};
my $obj = $self->{ARGS}->[0];
my $func = $obj->can($method);
die("cannot restore $self: can't locate method '$method' on object $obj")
unless defined $func;
$self->{FUNC} = $func;
return;
}
1;