How to compose an existing Moose role in a class at runtime?

Let's say I define an abstract implementation of My :: Object and the specific role My :: Object :: TypeA and My :: Object :: TypeB. For reasons of ease of maintenance, I would not want to have a hard-coded table that looks at the type of object and applies roles. As a DWIMmy example, I am looking for something in 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); } 

Let me get an object My :: Object with My :: Object :: TypeB by doing the following:

 my $obj = My::Object(id = 'foo') 

Will it do what I want, or am I on a completely wrong path?

Edit: I have simplified this too much; I do not want to know the type when I instantiate the object, I want the object to determine its type and apply the correct role methods accordingly. I edited my question to make this clearer.

+6
perl moose roles
source share
3 answers

You tried?

 $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' 

Productivity:

 $VAR1 = bless( { 'a' => 1 }, 'Class::MOP::Class::__ANON__::SERIAL::1' ); 

This is similar to what you want. Clear the code in the oose.pm call:

 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'); 
+7
source share

Use MooseX::Traits , it will turn your role into a trait that can be applied at runtime, then you simply 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(); 
+4
source share

After updating the question, I will give it another crack: with() is just a function call.

 package Class; use Moose; BEGIN { with ( map "MyObject::$_", qw/TypeA TypeB/ ); } 

Alternatively, you can reference the current package with the constant perl __PACKAGE__ .

+1
source share

All Articles