Reputation: 11963
I have a module that refuses to load unless a compile-time sanity check is met. Something like this:
package TopSecret;
use Moose;
die "Only Joe can use this!" unless $ENV{USER} eq 'joe';
1;
Now I would like to apply a similar sanity check to multiple modules, so my thought is to put it in a role. The consuming module would provide some information to customize the check a bit. So it might look something like:
package TopSecret;
use Moose;
with 'ForAuthorizedUser';
sub authorized_user { 'joe' }
1;
The problem is: how can I exercise TopSecret::authorized_user() from within ForAuthorizedUser, at compile time? Something like 'requires "authorized_user"' - except it would have to verify not just that the method exists, but execute it and check the return value.
Upvotes: 2
Views: 133
Reputation: 61510
I think that attribute overriding would be appropriate here. You declare the attribute in your Role and mark it as required, but don't provide a definition. Then the module that consumes the Role can supply the value for that attribute. Note that validation is typically done in the BUILD()
subroutine.
package ForAuthorizedUser;
use Moose::Role;
use Carp qw(croak); # so you can see the line it fails on
has 'authorized_user' => (
is => 'ro',
required => 1,
);
sub BUILD {
my ($self) = @_;
croak "Only Joe can use this!"
unless $self->authorized_user eq 'joe';
}
1;
Now in your module that consumes ForAuthorizedUser, you supply the definition for the attribute:
package TopSecret;
use Moose;
with qw(ForAuthorizedUser);
has '+authorized_user' => (
default => 'joe',
);
__PACKAGE__->meta->make_immutable;
In a separate module you do the same thing, but with a different name (mine):
package TopSecret2;
use Moose;
with qw(ForAuthorizedUser);
has '+authorized_user' => (
default => 'hunter',
);
__PACKAGE__->meta->make_immutable;
Then you could test this like so:
use TopSecret;
use TopSecret2;
TopSecret->new; # lives
TopSecret2->new # croaks Only Joe can use this! at constructor TopSecret2::new (defined at Test.pm line 35) line 36.
Upvotes: 1