use strict;
use warnings;
+our $VERSION = '0.63';
+$VERSION = eval $VERSION;
+our $AUTHORITY = 'cpan:STEVAN';
+
use List::MoreUtils qw( all );
+my @Classes = qw( constructor_class destructor_class error_class );
+
sub apply_metaclass_roles {
my %options = @_;
my $for = $options{for_class};
- my $meta = _make_new_metaclass( $for, \%options );
+ my %old_classes
+ = map { $_ => $for->meta->$_ } grep { $for->meta->can($_) } @Classes;
- for my $tor_class ( grep { $options{ $_ . '_roles' } }
- qw( constructor_class destructor_class ) ) {
+ my $meta = _make_new_metaclass( $for, \%options );
- my $class = _make_new_class(
- $meta->$tor_class(),
- $options{ $tor_class . '_roles' }
- );
+ for my $c ( grep { $meta->can($_) } @Classes ) {
+ if ( $options{ $c . '_roles' } ) {
+ my $class = _make_new_class(
+ $meta->$c(),
+ $options{ $c . '_roles' }
+ );
- $meta->$tor_class($class);
+ $meta->$c($class);
+ }
+ else {
+ $meta->$c( $old_classes{$c} );
+ }
}
return $meta;
my $old_meta = $for->meta();
- Class::MOP::remove_metaclass_by_name($for);
-
# This could get called for a Moose::Meta::Role as well as a Moose::Meta::Class
my %classes = map {
$_ => _make_new_class( $old_meta->$_(), $options->{ $_ . '_roles' } )
return $existing_class unless $roles;
- my $meta = $existing_class->meta();
+ my $meta = Class::MOP::Class->initialize($existing_class);
return $existing_class
if $meta->can('does_role') && all { $meta->does_role($_) } @{$roles};
This function will apply the specified roles to the object's base class.
+=head1 PROBLEMS WITH METACLASS ROLES AND SUBCLASS
+
+Because of the way this module works, there is an ordering problem
+which occurs in certain situations. This sequence of events causes an
+error:
+
+=over 4
+
+=item 1.
+
+There is a class (ClassA) which uses some extension(s) that apply
+roles to the metaclass.
+
+=item 2.
+
+You have another class (ClassB) which wants to subclass ClassA and
+apply some more extensions.
+
+=back
+
+Normally, the call to C<extends> will happen at run time, I<after> the
+additional extensions are applied. This causes an error when we try to
+make the metaclass for ClassB compatible with the metaclass for
+ClassA.
+
+We hope to be able to fix this in the future.
+
+For now the workaround is for ClassB to make sure it extends ClassA
+I<before> it loads extensions:
+
+ package ClassB;
+
+ use Moose;
+
+ BEGIN { extends 'ClassA' }
+
+ use MooseX::SomeExtension;
+
=head1 AUTHOR
Dave Rolsky E<lt>autarch@urth.orgE<gt>