Tuesday, March 6, 2012

before, after, and around Moose


One of the things I like about Moose is its method modifiers. They
provide an easy interface to modifying methods without disturbing
them. What's more is that they are stupidly simple.

the three modifiers are "before", "after", and "around". "before" and
"after" are simple in that they allow you to run code before or after
a given method So whether you want to ensure something happens
before you run a method:

  before 'wear_boots' => sub {
      my $self = shift;
      $self->wear_socks;
  };

 or after:

  after 'use_bathroom' => sub {
      my $self = shift;
      $self->wash_hands;
  };

You can be sure that you can make it happen without disturbing the way
that the method is supposed to run.

The "around" modifier provides a lot more flexibility. It receives the
original method, the object, and then any arguments that are passed to
it. This way you can execute the original method depending on your own logic:

  around 'eat' => sub {
      my $orig = shift;
      my $self = shift;

      if ($self->time_of day eq "morning") {
         $self->{meal_type} = "breakfast";
      }
      elsif ($self->time_of day eq "afternoon") {
         $self->{meal_type} = "lunch";
      }
      elseif ($self->time_of day eq "evening") {
         $self->{meal_type} = "dinner";
      }
      return $self->$orig(@)
  };

Moose is great because it provides a simple syntax that abbreviates OO
Perl's boilerplate requirements. These modifiers are a perfect example
of this. They make overriding methods easy. The relevant documentation in the cpan is here

8 comments:

  1. I hate to nitpick, but should those conditions in the around modified method be 'eq' and not '=='?

    ReplyDelete
  2. You are absolutely right. Good catch. I've corrected the problem. If anyone sees any other problems feel free to let me know.

    ReplyDelete
  3. You really shouldn't modify the underlying hashref directly when using Moose. That largely defeats the purpose of declaring attributes, and makes for much more fragile code.

    ReplyDelete
  4. "It receives the original method, the object, and then any methods that are passed to it."

    I think that should be "... any arguments that are passed to it."

    ReplyDelete
    Replies
    1. Thanks for letting me know. The error has been fixed.

      Delete
  5. Your call: return $self->$orig() should be $self->$orig(@_) or else you'll lose the original args to eat().

    ReplyDelete
  6. These modifiers are disastrous in a large project. I have a class $D that is 4 levels deep in an object hierarchy and that inherits from 7 different classes. I want to know what happens when I call $D->foo(). I have to trace all the way up the hierarchy, searching for ISA, base, extends, and parent (why did Moose introduce alternate syntax for doing the exact same thing no more conveniently?), then search for sub foo in each package, then ALSO search for around foo, before foo, and after foo in each class.

    ReplyDelete