+ - also inhale from Mouse
- clarify how isa and coerce interact
- support isa and coerce together for Moose
- guard _accessor_maker_for calls in Moo::Role in case Moo isn't loaded
Moo->_constructor_maker_for($target)
->register_attribute_specs(%{$old->all_attribute_specs});
}
+ $Moo::HandleMoose::MOUSE{$target} = [
+ grep defined, map Mouse::Util::find_meta($_), @_
+ ] if $INC{"Mouse.pm"};
$class->_maybe_reset_handlemoose($target);
};
_install_coderef "${target}::with" => "Moo::with" => sub {
Extending a L<Moose> class or consuming a L<Moose::Role> should also work.
+So should extending a L<Mouse> class or consuming a L<Mouse::Role>.
+
This means that there is no need for anything like L<Any::Moose> for Moo
-code - Moo and Moose code should simply interoperate without problem.
+code - Moo and Moose code should simply interoperate without problem. To
+handle L<Mouse> code, you'll likely need an empty Moo role or class consuming
+or extending the L<Mouse> stuff since it doesn't register true L<Moose>
+metaclasses like we do.
However, these features are new as of 0.91.0 (0.091000) so while serviceable,
they are absolutely certain to not be 100% yet; please do report bugs.
);
}
};
+
my %methods = %{Role::Tiny->_concrete_methods_of($name)};
# needed to ensure the method body is stable and get things named
Sub::Defer::undefer_sub($_) for grep defined, values %methods;
{
# This local is completely not required for roles but harmless
local @{_getstash($name)}{keys %methods};
+ my %seen_name;
foreach my $name (@$attr_order) {
+ $seen_name{$name} = 1;
my %spec = %{$attr_specs->{$name}};
delete $spec{index};
$spec{is} = 'ro' if $spec{is} eq 'lazy' or $spec{is} eq 'rwp';
}
push @attrs, $meta->add_attribute($name => %spec);
}
+ foreach my $mouse (do { our %MOUSE; @{$MOUSE{$name}||[]} }) {
+ foreach my $attr ($mouse->get_all_attributes) {
+ my %spec = %{$attr};
+ delete @spec{qw(
+ associated_class associated_methods __METACLASS__
+ provides curries
+ )};
+ my $name = delete $spec{name};
+ next if $seen_name{$name}++;
+ push @attrs, $meta->add_attribute($name => %spec);
+ }
+ }
}
if ($am_role) {
my $info = $Moo::Role::INFO{$name};
sub _inhale_if_moose {
my ($self, $role) = @_;
_load_module($role);
- if (!$INFO{$role} and $INC{"Moose.pm"}) {
- if (my $meta = Class::MOP::class_of($role)) {
- $INFO{$role}{methods} = {
- map +($_ => $role->can($_)),
- grep !$meta->get_method($_)->isa('Class::MOP::Method::Meta'),
- $meta->get_method_list
- };
- $Role::Tiny::APPLIED_TO{$role} = {
- map +($_->name => 1), $meta->calculate_all_roles
- };
- $INFO{$role}{requires} = [ $meta->get_required_method_list ];
- $INFO{$role}{attributes} = [
- map +($_ => $meta->get_attribute($_)), $meta->get_attribute_list
- ];
- my $mods = $INFO{$role}{modifiers} = [];
- foreach my $type (qw(before after around)) {
- my $map = $meta->${\"get_${type}_method_modifiers_map"};
- foreach my $method (keys %$map) {
- foreach my $mod (@{$map->{$method}}) {
- push @$mods, [ $type => $method => $mod ];
- }
+ my $meta;
+ if (!$INFO{$role}
+ and (
+ $INC{"Moose.pm"}
+ and $meta = Class::MOP::class_of($role)
+ )
+ or (
+ $INC{"Mouse.pm"}
+ and $meta = Mouse::Util::find_meta($role)
+ )
+ ) {
+ $INFO{$role}{methods} = {
+ map +($_ => $role->can($_)),
+ grep !$meta->get_method($_)->isa('Class::MOP::Method::Meta'),
+ $meta->get_method_list
+ };
+ $Role::Tiny::APPLIED_TO{$role} = {
+ map +($_->name => 1), $meta->calculate_all_roles
+ };
+ $INFO{$role}{requires} = [ $meta->get_required_method_list ];
+ $INFO{$role}{attributes} = [
+ map +($_ => $meta->get_attribute($_)), $meta->get_attribute_list
+ ];
+ my $mods = $INFO{$role}{modifiers} = [];
+ foreach my $type (qw(before after around)) {
+ # Mouse pokes its own internals so we have to fall back to doing
+ # the same thing in the absence of the Moose API method
+ my $map = $meta->${\(
+ $meta->can("get_${type}_method_modifiers_map")
+ or sub { shift->{"${type}_method_modifiers"} }
+ )};
+ foreach my $method (keys %$map) {
+ foreach my $mod (@{$map->{$method}}) {
+ push @$mods, [ $type => $method => $mod ];
}
}
- require Class::Method::Modifiers if @$mods;
- $INFO{$role}{inhaled_from_moose} = 1;
}
+ require Class::Method::Modifiers if @$mods;
+ $INFO{$role}{inhaled_from_moose} = 1;
}
}
}
BEGIN {
+ package Splat2;
+
+ use Mouse::Role;
+
+ requires 'monkey';
+
+ sub punch { 1 }
+
+ sub jab { 0 }
+
+ around monkey => sub { 'OW' };
+
+ has trap => (is => 'ro', default => sub { -1 });
+}
+
+BEGIN {
package Splattered;
use Moo;
sub jab { 3 }
}
-my $s = Splattered->new;
+BEGIN {
+ package Splattered2;
+
+ use Moo;
+
+ sub monkey { 'WHAT' }
+
+ with 'Splat2';
+
+ sub jab { 3 }
+}
-is($s->punch, 1, 'punch');
-is($s->jab, 3, 'jab');
-is($s->monkey, 'OW', 'monkey');
-is($s->trap, -1, 'trap');
+foreach my $s (Splattered->new, Splattered2->new) {
+ is($s->punch, 1, 'punch');
+ is($s->jab, 3, 'jab');
+ is($s->monkey, 'OW', 'monkey');
+ is($s->trap, -1, 'trap');
+}
done_testing;
--- /dev/null
+use strictures 1;
+use Test::More;
+
+{
+ package Tower1;
+
+ use Mouse;
+
+ has 'attr1' => (is => 'ro', required => 1);
+
+ package Tower2;
+
+ use Moo;
+
+ extends 'Tower1';
+
+ has 'attr2' => (is => 'ro', required => 1);
+
+ package Tower3;
+
+ use Moose;
+
+ extends 'Tower2';
+
+ has 'attr3' => (is => 'ro', required => 1);
+
+ __PACKAGE__->meta->make_immutable;
+}
+
+foreach my $num (1..3) {
+ my $class = "Tower${num}";
+ my @attrs = map "attr$_", 1..$num;
+ my %args = map +($_ => "${_}_value"), @attrs;
+ my $obj = $class->new(%args);
+ is($obj->{$_}, "${_}_value", "Attribute $_ ok for $class") for @attrs;
+}
+
+done_testing;