Extracting the metaclass from a parameterized role

2010-01-15 Thread Karen Etheridge


tl;dr version: no questions here, just some discoveries that I wanted to
spread a little farther and get google-indexed :)


A while back I posted on Stack Overflow about extracting the metaclass of
the currently-composing class from within the role definition:

http://stackoverflow.com/questions/1758884/how-can-i-access-the-meta-class-of-the-module-my-moose-role-is-being-applied-to

... which lead me to MooseX::Role::Parameterized (a continued two big
thumbs up BTW), which lead me to a few discoveries that I wanted to mention
here for posterity:

1. $args{consumer} only contains the metaclass of the target class at the
first level of parameterization. If the parameterized role (Role::A) is further
including another parameterized role (Role::B), then $args{consumer} in
Role::B will actually contain the metaclass of the first parameterized role
(MooseX::Role::Parameterized::Meta::Role::Parameterized), rather than
(a possible subclass of) Moose::Meta::Class.

In my application I'm nesting parameterized roles a few levels deep (the
code is cleaner this way rather than having lots of nested if statements),
so I've added a 'meta' parameter to the list of params being passed around:

# when calling the sub-role:
role {
# isa Moose::Meta::Class
my $meta = $args{consumer};

with Role::B = {
# other parameters...
metaclass = $meta,
};
};

# and in the subrole:
parameter metaclass = (
is = 'ro', isa = 'Moose::Meta::Class',
required = 1,
);

role {
# isa Moose::Meta::Class
my $meta = $params-metaclass;

};



2. $args{consumer} won't even be a metaclass in the case of a role
application to a specific object instance -- in this case it will be the
type of the object being applied to.

role {
my $meta = $args{consumer};
$meta = $meta-meta if not $meta-isa('Moose::Meta::Class');

};


Neither of these discoveries seemed obvious at first, so I wanted to pass
it on to save others some heartache.  I wonder if the true metaclass
should perhaps be available via some sort of method call, to avoid the
backflips I've done above -- I'm using all the code above as boilerplate in
all my parameterized roles now.


PS. Earlier today I was about to post here asking how one could apply a
parameterized role to an object instance (as there was no example in the
documentation), but in stepping through the Moose guts I discovered that
indeed it is just as simple as for non-parameterized roles: (oh happy day)

my $foo = My::Foo-new();
Moose::Util::apply_all_roles($foo, My::Role, { parameter = 'value' });




Re: Extracting the metaclass from a parameterized role

2010-01-15 Thread Hans Dieter Pearcey
Excerpts from Karen Etheridge's message of Fri Jan 15 19:57:14 -0500 2010:
 ... which lead me to MooseX::Role::Parameterized (a continued two big
 thumbs up BTW), which lead me to a few discoveries that I wanted to mention
 here for posterity:

I feel like a lot of this stuff works by accident and should either be
explicitly forbidden or documented and cleaned up.

Shawn, what do you think? It's your baby.

hdp.


Extracting the metaclass from a parameterized role

2010-01-15 Thread Karen Etheridge
(Apologies if this is a dupe; I've tried sending this a few times today and
have been experiencing issues with my msmtp configs.)


tl;dr version: no questions here, just some discoveries that I wanted to
spread a little farther and get google-indexed :)


A while back I posted on Stack Overflow about extracting the metaclass from
inside a role definition:

http://stackoverflow.com/questions/1758884/how-can-i-access-the-meta-class-of-the-module-my-moose-role-is-being-applied-to

... which lead me to MooseX::Role::Parameterized (a continued two big
thumbs up BTW), which lead me to a few discoveries that I wanted to mention
here for posterity:

1. $args{consumer} only contains the metaclass of the target class at the
first level of parameterization. If the parameterized role (Role::A) is further
including another parameterized role (Role::B), then $args{consumer} in
Role::B will actually contain the metaclass of the first parameterized role
(MooseX::Role::Parameterized::Meta::Role::Parameterized), rather than
(a possible subclass of) Moose::Meta::Class.

In my application I'm nesting parameterized roles a few levels deep (the
code is cleaner this way rather than having lots of nested if statements),
so I've added a 'meta' parameter to the list of params being passed around:

# when calling the sub-role:
role {
# isa Moose::Meta::Class
my $meta = $args{consumer};

with Role::B = {
# other parameters...
metaclass = $meta,
};
};

# and in the subrole:
parameter metaclass = (
is = 'ro', isa = 'Moose::Meta::Class',
required = 1,
);

role {
# isa Moose::Meta::Class
my $meta = $params-metaclass;

# isa Moose::Object
my $consumer = $meta-name;
};



2. $args{consumer} won't even be a metaclass in the case of a role
application to a specific object instance -- in this case it will be the
type of the object being applied to.

role {
my $meta = $args{consumer};
$meta = $meta-meta if not $meta-isa('Moose::Meta::Class');

# isa Moose::Object
my $consumer = $meta-name;
};


Neither of these discoveries seemed obvious at first, so I wanted to pass
it on to save others some heartache.

I wonder if it might be useful to offer an API to extract the metaclass, as
the code above has essentially become boilerplate for all my parameterized
roles..


PS. Earlier today I was about to post here asking how one could apply a
parameterized role to an object instance (as there was no example in the
documentation), but in stepping through the Moose guts I discovered that
indeed it is just as simple as for non-parameterized roles:

my $foo = My::Foo-new();
Moose::Util::apply_all_roles($foo, My::Role, { parameter = 'value' });