I have a Moo(se)[0] class with a number of methods which have the exact same type of "guard statement" at the top. Instead of writing the same code several of times I figured I could put the statement in a "before" method modifier, and that works perfectly. Unless this class is subclassed, because then the "before guard" is never called.
package Foo;
use feature 'say';
use Moose;
has '_init' => (
is => 'rw',
isa => 'Bool',
default => 0
);
sub init {
shift->_init(1);
}
sub method {
say "in Foo::method";
}
before method => sub {
my $self = shift;
warn "==> Foo is not initialized\n" unless $self->_init;
};
package Bar;
use feature 'say';
use Moose;
extends 'Foo';
sub method {
say "in Bar::method";
}
package main;
use feature 'say';
my $foo = Foo->new;
say "foo the wrong way:";
$foo->method;
say "foo the right way:";
$foo->init;
$foo->method;
my $bar = Bar->new;
say "bar the wrong way:";
$bar->method;
Output is then (with some added new lines):
foo the wrong way:
==> Foo is not initialized
in Foo::method
foo the right way:
in Foo::method
bar the wrong way:
in Bar::method
I assume this behaviour is by design, but is there any (nice) way to make sure all subclasses also inherit the "before" method modifier/guard statement? Or is there a different way to accomplish this (I suspect it's a rather common construct). Note that an exception will be thrown in the real guard statement, but a "warn" is much simpler in example code.
[0] I prefer to use Moo because I don't use any features requiring MOP, but both Moo and Moose works the exact same way in this matter.
Edit using Roles.
If a add a Role
for this (as suggested by tobyink), and add another method for making things a bit more 'real life', I get a peculiar result.
package Warning::NotInit;
use feature 'say';
use Moose::Role;
has '_init' => (is => 'rw', isa => 'Bool', default => 0);
before qw/ m1 m2 / => sub {
my $self = shift;
my $class = ref($self);
warn "==> $class is not initialized\n" unless $self->_init;
};
package Foo;
use feature 'say';
use Moose;
with 'Warning::NotInit';
sub init { shift->_init(1) }
sub m1 { say "in Foo::m1" }
sub m2 { say "in Foo::m2" }
package Bar;
use feature 'say';
use Moose;
extends 'Foo';
with 'Warning::NotInit';
sub m1 { say "in Bar::m1" }
package main;
use feature 'say';
When calling the not overridden method in the subclass, the before
method is called twice.
my $bar = Bar->new;
say "bar the wrong way:";
$bar->m1;
$bar->m2;
Output:
bar the wrong way:
==> Bar is not initialized
in Bar::m1
==> Bar is not initialized
==> Bar is not initialized
in Foo::m2
Why is it called twice?