Taming the Moose: Method modifiers instead of overrides in object-oriented Perl

Last month I wrote about using Moose’s override function to, well, override a superclass’s method. Chris Prather on the #moose IRC channel suggested soon after that the around method modifier (or its little sisters before and after) might be a better c…


This content originally appeared on DEV Community and was authored by Mark Gardner

Last month I wrote about using Moose’s override function to, well, override a superclass’s method. Chris Prather on the #moose IRC channel suggested soon after that the around method modifier (or its little sisters before and after) might be a better choice if you’re also calling the original method inside. He noted that “at a minimum override only works if you’re subclassing, around will apply to composed methods too.”

His point was that when you decide to compose roles (also know as traits) instead of or in addition to more traditional inheritance, override simply doesn’t work: only a method modifier will do. (And as Graham Knop and Karen Etheridge later remarked on IRC, override isn’t even an option if you’re using Moo as an alternative to Moose.)

Modifying a role’s method with around might look like this:

#!/usr/bin/env perl

use v5.12; # for strict and say
use warnings;

package Local::Role::Hungry;
use Moose::Role;
requires 'name';

sub wants_food {
    my $self = shift;
    say $self->name, ' is hungry!';
    return;
}

package Local::GuineaPig;
use Moose;
has name => (is => 'ro');
with 'Local::Role::Hungry';

around wants_food => sub {
    my ($orig, $self) = splice @_, 0, 2;
    say $self->name, ' runs to the front of the cage!';
    $self->$orig(@_);
    say 'Wheek!';
    return;
};

package Local::Dog;
use Moose;
has name => (is => 'ro');
with 'Local::Role::Hungry';

around wants_food => sub {
    my ($orig, $self) = splice @_, 0, 2;
    say $self->name, ' runs to the kitchen!';
    $self->$orig(@_);
    say 'Woof!';
    return;
};

before wants_food => sub {
    my $self = shift;
    say $self->name, ' is jumping!';
};

package main;
my $dog = Local::Dog->new(name => 'Seamus');
my @pigs = map { Local::GuineaPig->new(name => $_) }
  qw<Cocoa Ginger Pepper>;

for my $animal ($dog, @pigs) {
    $animal->wants_food();
}

Running the above yields:

Seamus runs to the kitchen!
Seamus is hungry!
Woof!
Cocoa runs to the front of the cage!
Cocoa is hungry!
Wheek!
Ginger runs to the front of the cage!
Ginger is hungry!
Wheek!
Pepper runs to the front of the cage!
Pepper is hungry!
Wheek!

It’s a little more involved than overriding a sub, since method modifiers are passed both the consumed role’s original method ($orig above) and the instance ($self above) as parameters. It has the same effect, though, and you can call the original method by saying $self->$orig(parameters). That’s why I used the splice function so I could pass any remaining parameters as the original @_ array.

If all you want to do is have something happen either before or after the original method, just use before or after:

before wants_food => sub {
    my $self = shift;
    say $self->name, ' is jumping!';
};

Note that there’s no return value in a before or after modifier, as those are handled by the original method.

Modifiers aren’t limited to consuming classes; they can be in roles and modify their consumers’ methods. They also have a couple of other tricks:

  • You can pass an array reference to modify multiple methods at once.
  • You can use the contents of a variable to specify the modified method name, and use that same variable in the modifier itself.
  • You can use a regular expression to select methods. (Beware if you’re using Moo that its Class::Method::Modifiers module doesn’t support this.)

Putting these together gives you constructs like these:

after qw<foo bar baz> => sub {
    say 'Something got called';
};

for my $method_name (qw<foo bar baz>) {
    before $method_name => sub {
        say "Calling $method_name...";
    };
}

before qr/^request_/ => sub {
    my ($self, @args) = @_;
    $self->is_valid(@args) or die 'Invalid arguments';
};

Moose comes with great introductory manuals for method modifiersand roles, so be sure to check those out. There’s a lot more to them and a blog can only cover so much.


This content originally appeared on DEV Community and was authored by Mark Gardner


Print Share Comment Cite Upload Translate Updates
APA

Mark Gardner | Sciencx (2021-08-31T14:00:00+00:00) Taming the Moose: Method modifiers instead of overrides in object-oriented Perl. Retrieved from https://www.scien.cx/2021/08/31/taming-the-moose-method-modifiers-instead-of-overrides-in-object-oriented-perl/

MLA
" » Taming the Moose: Method modifiers instead of overrides in object-oriented Perl." Mark Gardner | Sciencx - Tuesday August 31, 2021, https://www.scien.cx/2021/08/31/taming-the-moose-method-modifiers-instead-of-overrides-in-object-oriented-perl/
HARVARD
Mark Gardner | Sciencx Tuesday August 31, 2021 » Taming the Moose: Method modifiers instead of overrides in object-oriented Perl., viewed ,<https://www.scien.cx/2021/08/31/taming-the-moose-method-modifiers-instead-of-overrides-in-object-oriented-perl/>
VANCOUVER
Mark Gardner | Sciencx - » Taming the Moose: Method modifiers instead of overrides in object-oriented Perl. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/08/31/taming-the-moose-method-modifiers-instead-of-overrides-in-object-oriented-perl/
CHICAGO
" » Taming the Moose: Method modifiers instead of overrides in object-oriented Perl." Mark Gardner | Sciencx - Accessed . https://www.scien.cx/2021/08/31/taming-the-moose-method-modifiers-instead-of-overrides-in-object-oriented-perl/
IEEE
" » Taming the Moose: Method modifiers instead of overrides in object-oriented Perl." Mark Gardner | Sciencx [Online]. Available: https://www.scien.cx/2021/08/31/taming-the-moose-method-modifiers-instead-of-overrides-in-object-oriented-perl/. [Accessed: ]
rf:citation
» Taming the Moose: Method modifiers instead of overrides in object-oriented Perl | Mark Gardner | Sciencx | https://www.scien.cx/2021/08/31/taming-the-moose-method-modifiers-instead-of-overrides-in-object-oriented-perl/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.