5

I have a Moose::Role that I would like to call some extra subs on the class when that role is applied to the class.

Is there an easy way to modify what happens when the role is applied, without having to dig too much into Moose::Meta::Role type coding? Ideally, I'd just like to after 'apply' => ... to add the extra stuff.

Edit:

I'm specifically using this with a DBIx::Class::Core result definition to create something like a component that also modifies the constructor. I would just write it as a component if I could get at BUILDARGS and BUILD subs for the result, but I can't seem to do. So, instead of doing load_component, I doing with 'role', but some of the effects of the component are to add belongs_to relationships to the class. Hence, I was thinking the best way to do that is during application of the role to the class.

Carl
  • 7,538
  • 1
  • 40
  • 64
  • 1
    Can you clarify a bit more what you want to do? What would you put in your hypothetical `after 'apply'` sub? Such tinkering with the MOP is not normally done, so there is almost certainly an easier way of accomplishing what you want to do. – Ether Oct 31 '10 at 17:53
  • @Ether: sure, edited in a little more explanation. – Carl Oct 31 '10 at 18:23
  • Have you tried `after BUILD => sub { ... }` in your role? – Ether Oct 31 '10 at 18:33
  • @Ether: yes, that's works - that's why I'm doing it as a role. However, some of things that can be done in a component I can't seem to do in a role (like adding relationships). Currently, I've written a component that loads the role in addition to doing component-y things - but that just seems silly. It should all be in one place. – Carl Oct 31 '10 at 18:51

3 Answers3

4

In a briefly-lived comment I referred you to this question, which discusses how to access the metaclass of the class the role is being applied to (e.g. so you can build onto the class conditionally). However, that's a really stinky use of MooseX::Role::Parameterized providing you that information, and it also won't work if the role is being applied to another role, not to a class.

As an alternative, you could write a sugar function which receives the meta information, and build onto the class in that way:

sub foo
{
     my ($meta, %options) = @_;

     # based on what is present in %options, add additional attributes...
     $meta->add_attribute(...);
}

See Moose::Cookbook::Extending::Recipe4 for an example of writing sugar functions.

Community
  • 1
  • 1
Ether
  • 53,118
  • 13
  • 86
  • 159
  • what do you think of using traits to modify Moose::Meta::Role? that's described in the docs as the way to make simple modifications to the meta role. – Carl Oct 31 '10 at 21:47
1

You could use a parameterized role. There is an example on how to access the consuming class in the tutorial. That being said, I would advise you to join the Moose and DBIx-Class IRC channels or mailing lists to look for best-practices in this regard.

phaylon
  • 1,914
  • 14
  • 13
0

What I found that works, is compact, and seems in keeping with intent in the docs is to use a trait to modify the meta role used by my particular role:

package DBIx::Class::Meta::Role::MyRole;
use Moose;
BEGIN { extends 'Moose::Meta::Role'; }
after 'apply' => sub {
## ..my mods to add extra relationships to DBIx::Class::Core result
};
no Moose;

package DBIx::Class::MyRole;
use Moose::Role -metaclass => 'DBIx::Class::Meta::Role::MyRole';
Carl
  • 7,538
  • 1
  • 40
  • 64