http://qs1969.pair.com?node_id=979192

elTriberium has asked for the wisdom of the Perl Monks concerning the following question:

Is the following possible with Moose?

I have a class which has an object of another class as an attribute:

package My::ABC has 'db_accessor' => ( is => 'rw', isa => 'My::DEF', );

Inside this DEF class there are multiple methods which are called from ABC. They throw exceptions on errors (die). However, in this special case of class ABC I don't want the script to die, I want it to continue. At the same time I don't want to put an "eval" around each method call of "db_accessor".

I already tried to use the "around" modifier of Moose, but that seems to only work for the constructor, not for the method calls on "db_accessor". I tried it like this:

around 'db_accessor => sub { my $orig = shift; my $self = shift; my $out; eval { $out = $self->$orig(@_) }; if ($@) { $self->warn("Access failed with: [$@]"); } else { return $out; } };

However, this doesn't work. An access in this form still causes the script to die: $self->db_accessor->methodA();

Any idea how to solve this with Moose? Thanks in advance!

Replies are listed 'Best First'.
Re: Intercept all object method calls with Moose
by tobyink (Canon) on Jun 30, 2012 at 07:10 UTC

    It's not the db_accessor method call that is dying, but the methodA accessor.

    What you need to do is subclass My::DEF...

    package My::DEF::JohnMacLane; # because it doesn't die use Moose; extends 'My::DEF'; my @make_immortal = qw( methodA methodB ); foreach my $meth (@make_immortal) { around $meth => sub { my ($orig, $self, @args) = @_; return eval { $self->$orig(@args) }; }; } 1;

    The other possibility is to write a Shield class that sits in between My::ABC and My::DEF. I'm in a rush now, but I may update this post later with an example...

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      OK, thanks, I understand that the methodA accessor call was dying, I was only wondering whether I could somehow easily intercept ALL method calls of an attribute in the calling class. In your example (which is helpful, thanks for that), it's not the calling class, but the called class which intercepts the methods.

      I'll have to think about if I want to use it this way, it's effectively a new derived class just for this. Maybe just handling it manually in the calling class (by putting an eval around each method call) is the better way to go. Thanks for your input again!

Re: Intercept all object method calls with Moose
by tobyink (Canon) on Jul 02, 2012 at 20:31 UTC

    OK, here's an example of a "shield class": Die::Hard. I'm surprised I couldn't find anything similar on CPAN. Do people think it's worthy of releasing?

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'