[Pdx-pm] [build in defaults to method calls from the outside] need some help thinking thru this one
Michael G Schwern
schwern at pobox.com
Mon Jul 23 22:06:24 PDT 2007
benh wrote:
> It works, but it seems needlessly messy. What I would like to do is to
> have some way to specify that all calls made to SingleBook that dont
> exits should then get passed to BookInfo with the know isbn.
>
> I was thinking of doing something along these lines:
>
> if ($self->can($action) ) {
> return $self->$action;
> } elseif ($self->{bi}->can($action) {
> return $self->{bi}->$action($self->{isbn});
> } else {
> die 'freakout... why are we here?';
> }
>
> ... but I would have no idea where to plug this in to intercept every
> call to this object, unless I build a sub that EVERYTHING goes thru...
> but thats alot of code to change, and again seems like a very cludgy
> way to trap things.
>
> Any one have any other ideas? Am I on the right track? Completely
> missed the mark?
AUTOLOAD() is the method which gets called if Perl can't find a method. Its
called with the same arguments as a regular method. The original fully
qualified method name called is in $AUTOLOAD.
our $AUTOLOAD;
sub AUTOLOAD {
my $self = shift;
my $class = ref $self || $self;
my($method) = $AUTOLOAD =~ m/:([^:]+)$/;
return if $method eq 'DESTROY';
if( $self->{bi}->can($method) ) {
return $self->{bi}->$method($self->{isbn}, @_);
}
else {
croak sprintf
q[Can't locate object method "%s" via package "%s"],
$method, ref $self;
}
}
Since AUTOLOAD is overhead on each method call you can get tricksy. The first
time a method is called AUTOLOAD makes one for it. Then each call after a
real method is called.
our $AUTOLOAD;
sub AUTOLOAD {
my $self = $_[0];
my $class = ref $self || $self;
my($method) = $AUTOLOAD =~ m/:([^:]+)$/;
return if $method eq 'DESTROY';
if( $self->{bi}->can($method) ) {
my $code = sub {
my $self = shift;
$self->{bi}->$method($self->{isbn}, @_);
};
*{$class .'::'. $method} = $code;
goto $code;
}
else {
croak sprintf
q[Can't locate object method "%s" via package "%s"],
$method, ref $self;
}
}
To complete the illusion, override can() so it can answer correctly for the
autoloaded methods which haven't been called yet.
sub can {
my($self, $method) = @_;
return 1 if $self->can($method);
return 1 if $self->{bi}->can($method);
return 0;
}
More information about the Pdx-pm-list
mailing list