which returns the role which first defined an attribute. See the docs for
details. (Dave Rolsky)
+ * Moose::Util::MetaRole will make sure that the class to which you're
+ applying metaroles or base class roles can actually have them applied. If
+ not (it's not a Moose class, it has a non-Moose metaclass, etc.), then it
+ gives a useful error message. Previously, this would just end up dying in
+ the MetaRole code without a useful message. (Dave Rolsky)
+
[BUG FIXES]
* When a role had its own applied_attribute metaclass (usually from MetaRole
use warnings;
use Scalar::Util 'blessed';
+use Carp qw( croak );
use List::MoreUtils qw( all );
use List::Util qw( first );
use Moose::Deprecated;
+use Scalar::Util qw( blessed );
sub apply_metaclass_roles {
Moose::Deprecated::deprecated(
_fixup_old_style_args(\%args);
- my $for
- = blessed $args{for}
- ? $args{for}
- : Class::MOP::class_of( $args{for} );
+ my $for = _metathing_for( $args{for} );
if ( $for->isa('Moose::Meta::Role') ) {
return _make_new_metaclass( $for, $args{role_metaroles}, 'role' );
}
}
+sub _metathing_for {
+ my $passed = shift;
+
+ my $found
+ = blessed $passed
+ ? $passed
+ : Class::MOP::class_of($passed);
+
+ return $found
+ if defined $found
+ && blessed $found
+ && ( $found->isa('Moose::Meta::Role')
+ || $found->isa('Moose::Meta::Class') );
+
+ local $Carp::CarpLevel = $Carp::CarpLevel + 1;
+
+ my $error_start
+ = 'When using Moose::Util::MetaRole, you must pass a Moose class name,'
+ . ' role name, metaclass object, or metarole object.';
+
+ if ( defined $found && blessed $found ) {
+ croak $error_start
+ . " You passed $passed, and we resolved this to a "
+ . ( blessed $found )
+ . ' object.';
+ }
+
+ if ( defined $passed && !defined $found ) {
+ croak $error_start
+ . " You passed $passed, and this did not resolve to a metaclass or metarole."
+ . ' Maybe you need to call Moose->init_meta to initialize the metaclass first?';
+ }
+
+ if ( !defined $passed ) {
+ croak $error_start
+ . " You passed an undef."
+ . ' Maybe you need to call Moose->init_meta to initialize the metaclass first?';
+ }
+}
+
sub _fixup_old_style_args {
my $args = shift;
sub apply_base_class_roles {
my %args = @_;
- my $for = $args{for} || $args{for_class};
-
- my $meta = Class::MOP::class_of($for);
+ my $meta = _metathing_for( $args{for} || $args{for_class} );
+ croak 'You can only apply base class roles to a Moose class, not a role.'
+ if $meta->isa('Moose::Meta::Role');
my $new_base = _make_new_class(
- $for,
+ $meta->name,
$args{roles},
[ $meta->superclasses() ],
);
);
}
+{
+ package NotMoosey;
+
+ use metaclass;
+}
+
+{
+ like(
+ exception {
+ Moose::Util::MetaRole::apply_metaroles(
+ for => 'Does::Not::Exist',
+ class_metaroles => { class => ['Role::Foo'] },
+ );
+ },
+ qr/When using Moose::Util::MetaRole.+You passed Does::Not::Exist.+Maybe you need to call.+/,
+ 'useful error when apply metaroles to a class without a metaclass'
+ );
+
+ like(
+ exception {
+ Moose::Util::MetaRole::apply_metaroles(
+ for => 'NotMoosey',
+ class_metaroles => { class => ['Role::Foo'] },
+ );
+ },
+ qr/When using Moose::Util::MetaRole.+You passed NotMoosey.+we resolved this to a Class::MOP::Class object.+/,
+ 'useful error when using apply metaroles to a class with a Class::MOP::Class metaclass'
+ );
+
+ like(
+ exception {
+ Moose::Util::MetaRole::apply_base_class_roles(
+ for => 'NotMoosey',
+ roles => { class => ['Role::Foo'] },
+ );
+ },
+ qr/When using Moose::Util::MetaRole.+You passed NotMoosey.+we resolved this to a Class::MOP::Class object.+/,
+ 'useful error when applying base class to roles to a non-Moose class'
+ );
+
+ like(
+ exception {
+ Moose::Util::MetaRole::apply_base_class_roles(
+ for => 'My::Role',
+ roles => { class => ['Role::Foo'] },
+ );
+ },
+ qr/You can only apply base class roles to a Moose class.+/,
+ 'useful error when applying base class to roles to a non-Moose class'
+ );
+}
+
done_testing;