Say I define an abstract My::Object and concrete role implementations My::Object::TypeA and My::Object::TypeB. For maintainability reasons, I'd like to not have a hardcoded table that looks at the object type and applies roles. As a DWIMmy example, I'm looking for something along these lines in My::Object:
has => 'id' (isa => 'Str', required => 1);
sub BUILD {
my $self = shift;
my $type = $self->lookup_type(); ## Returns 'TypeB'
{"My::Object::$type"}->meta->apply($self);
}
Letting me get a My::Object with My::Object::TypeB role applied by doing the following:
my $obj = My::Object(id = 'foo')
Is this going to do what I want or am I on the entirely wrong track?
Edit: I simplified this too much; I don't want to have to know the type when I instantiate the object, I want the object to determine its type and apply the correct role's methods appropriately. I've edited my question to make this clearer.
Have you tried it?
$perl -Moose -E'
sub BUILD { my ($self, $p) = @_; my $role = qq[Class::$$p{role}]; $role->meta->apply($self) };
package Class::A; use Moose::Role; has a => (is => q[ro], default => 1);
package main; say Class->new(role => q[A])->dump'
Yields:
$VAR1 = bless( {
'a' => 1
}, 'Class::MOP::Class::__ANON__::SERIAL::1' );
This appears to be what you want. Cleaned up the code in the oose.pm call is:
package Class;
use Moose;
sub BUILD {
my ($self, $p) = @_;
my $role = qq[Class::$$p{role}];
$role->meta->apply($self);
}
package Class::A;
use Moose::Role;
has a => ( is => 'ro', default => 1 );
package main;
Class->new(role => 'A');
Use MooseX::Traits
, it will turn your role into a trait that can be applied at runtime, then you just call:
# Where Class is a class that has `use MooseX::Traits`;
# And TypeB is a simple role
Class->new_with_traits( traits => [qw/TypeB/] )
# or even the new, and now preferred method.
Class->with_traits('TypeB')->new();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With