rename alias and excludes to -alias and -excludes
[gitmo/Moose.git] / lib / Moose / Meta / Role.pm
index dcca38f..a01a8db 100644 (file)
@@ -8,14 +8,16 @@ use metaclass;
 use Scalar::Util 'blessed';
 use Carp         'confess';
 use Sub::Name    'subname';
+use Devel::GlobalDestruction 'in_global_destruction';
 
-our $VERSION   = '0.76';
+our $VERSION   = '0.89';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
 use Moose::Meta::Class;
 use Moose::Meta::Role::Method;
 use Moose::Meta::Role::Method::Required;
+use Moose::Meta::Role::Method::Conflicting;
 
 use base 'Class::MOP::Module';
 
@@ -56,7 +58,7 @@ foreach my $action (
         attr_reader => 'get_excluded_roles_map' ,
         methods     => {
             add       => 'add_excluded_roles',
-            get_list  => 'get_excluded_roles_list',
+            get_keys  => 'get_excluded_roles_list',
             existence => 'excludes_role',
         }
     },
@@ -64,10 +66,9 @@ foreach my $action (
         name        => 'required_methods',
         attr_reader => 'get_required_methods_map',
         methods     => {
-            add       => 'add_required_methods',
-            remove    => 'remove_required_methods',
-            get_list  => 'get_required_method_list',
-            existence => 'requires_method',
+            remove     => 'remove_required_methods',
+            get_values => 'get_required_method_list',
+            existence  => 'requires_method',
         }
     },
     {
@@ -75,7 +76,7 @@ foreach my $action (
         attr_reader => 'get_attribute_map',
         methods     => {
             get       => 'get_attribute',
-            get_list  => 'get_attribute_list',
+            get_keys  => 'get_attribute_list',
             existence => 'has_attribute',
             remove    => 'remove_attribute',
         }
@@ -97,10 +98,15 @@ foreach my $action (
         $self->$attr_reader->{$_} = undef foreach @values;
     }) if exists $methods->{add};
 
-    $META->add_method($methods->{get_list} => sub {
+    $META->add_method($methods->{get_keys} => sub {
         my ($self) = @_;
         keys %{$self->$attr_reader};
-    }) if exists $methods->{get_list};
+    }) if exists $methods->{get_keys};
+
+    $META->add_method($methods->{get_values} => sub {
+        my ($self) = @_;
+        values %{$self->$attr_reader};
+    }) if exists $methods->{get_values};
 
     $META->add_method($methods->{get} => sub {
         my ($self, $name) = @_;
@@ -124,12 +130,42 @@ $META->add_attribute(
     default => 'Moose::Meta::Role::Method',
 );
 
+$META->add_attribute(
+    'required_method_metaclass',
+    reader  => 'required_method_metaclass',
+    default => 'Moose::Meta::Role::Method::Required',
+);
+
+$META->add_attribute(
+    'conflicting_method_metaclass',
+    reader  => 'conflicting_method_metaclass',
+    default => 'Moose::Meta::Role::Method::Conflicting',
+);
+
+$META->add_attribute(
+    'application_to_class_class',
+    reader  => 'application_to_class_class',
+    default => 'Moose::Meta::Role::Application::ToClass',
+);
+
+$META->add_attribute(
+    'application_to_role_class',
+    reader  => 'application_to_role_class',
+    default => 'Moose::Meta::Role::Application::ToRole',
+);
+
+$META->add_attribute(
+    'application_to_instance_class',
+    reader  => 'application_to_instance_class',
+    default => 'Moose::Meta::Role::Application::ToInstance',
+);
+
 ## some things don't always fit, so they go here ...
 
 sub add_attribute {
     my $self = shift;
     my $name = shift;
-    unless ( defined $name && $name ) {
+    unless ( defined $name ) {
         require Moose;
         Moose->throw_error("You must provide a name for the attribute");
     }
@@ -143,6 +179,34 @@ sub add_attribute {
     $self->get_attribute_map->{$name} = $attr_desc;
 }
 
+sub add_required_methods {
+    my $self = shift;
+
+    for (@_) {
+        my $method = $_;
+        if (!blessed($method)) {
+            $method = $self->required_method_metaclass->new(
+                name => $method,
+            );
+        }
+        $self->get_required_methods_map->{$method->name} = $method;
+    }
+}
+
+sub add_conflicting_method {
+    my $self = shift;
+
+    my $method;
+    if (@_ == 1 && blessed($_[0])) {
+        $method = shift;
+    }
+    else {
+        $method = $self->conflicting_method_metaclass->new(@_);
+    }
+
+    $self->add_required_methods($method);
+}
+
 ## ------------------------------------------------------------------
 ## method modifiers
 
@@ -168,7 +232,8 @@ foreach my $modifier_type (qw[ before around after ]) {
     $META->add_method("get_${modifier_type}_method_modifiers" => sub {
         my ($self, $method_name) = @_;
         #return () unless exists $self->$attr_reader->{$method_name};
-        @{$self->$attr_reader->{$method_name}};
+        my $mm = $self->$attr_reader->{$method_name};
+        $mm ? @$mm : ();
     });
 
     $META->add_method("has_${modifier_type}_method_modifiers" => sub {
@@ -431,18 +496,19 @@ sub apply {
     (blessed($other))
         || Moose->throw_error("You must pass in an blessed instance");
 
+    my $application_class;
     if ($other->isa('Moose::Meta::Role')) {
-        require Moose::Meta::Role::Application::ToRole;
-        return Moose::Meta::Role::Application::ToRole->new(@args)->apply($self, $other);
+        $application_class = $self->application_to_role_class;
     }
     elsif ($other->isa('Moose::Meta::Class')) {
-        require Moose::Meta::Role::Application::ToClass;
-        return Moose::Meta::Role::Application::ToClass->new(@args)->apply($self, $other);
+        $application_class = $self->application_to_class_class;
     }
     else {
-        require Moose::Meta::Role::Application::ToInstance;
-        return Moose::Meta::Role::Application::ToInstance->new(@args)->apply($self, $other);
+        $application_class = $self->application_to_instance_class;
     }
+
+    Class::MOP::load_class($application_class);
+    return $application_class->new(@args)->apply($self, $other);
 }
 
 sub combine {
@@ -453,10 +519,14 @@ sub combine {
 
     my (@roles, %role_params);
     while (@role_specs) {
-        my ($role, $params) = @{ splice @role_specs, 0, 1 };
-        push @roles => Class::MOP::class_of($role);
+        my ($role_name, $params) = @{ splice @role_specs, 0, 1 };
+        my $requested_role = Class::MOP::class_of($role_name);
+
+        my $actual_role = $requested_role->_role_for_combination($params);
+        push @roles => $actual_role;
+
         next unless defined $params;
-        $role_params{$role} = $params;
+        $role_params{$actual_role->name} = $params;
     }
 
     my $c = Moose::Meta::Role::Composite->new(roles => \@roles);
@@ -467,6 +537,11 @@ sub combine {
     return $c;
 }
 
+sub _role_for_combination {
+    my ($self, $params) = @_;
+    return $self;
+}
+
 sub create {
     my ( $role, $package_name, %options ) = @_;
 
@@ -555,7 +630,7 @@ sub create {
     sub DESTROY {
         my $self = shift;
 
-        return if Class::MOP::in_global_destruction(); # it'll happen soon anyway and this just makes things more complicated
+        return if in_global_destruction(); # it'll happen soon anyway and this just makes things more complicated
 
         no warnings 'uninitialized';
         return unless $self->name =~ /^$ANON_ROLE_PREFIX/;
@@ -591,7 +666,7 @@ sub create {
 # has 'roles' => (
 #     metaclass => 'Collection::Array',
 #     reader    => 'get_roles',
-#     isa       => 'ArrayRef[Moose::Meta::Roles]',
+#     isa       => 'ArrayRef[Moose::Meta::Role]',
 #     default   => sub { [] },
 #     provides  => {
 #         'push' => 'add_role',
@@ -627,7 +702,7 @@ sub create {
 # has 'required_methods' => (
 #     metaclass => 'Collection::Hash',
 #     reader    => 'get_required_methods_map',
-#     isa       => 'HashRef[Str]',
+#     isa       => 'HashRef[Moose::Meta::Role::Method::Required]',
 #     provides  => {
 #         # not exactly set, or delete since it works for multiple
 #         'set'    => 'add_required_methods',
@@ -737,8 +812,8 @@ This method creates a new role object with the provided name.
 
 This method accepts a list of array references. Each array reference
 should contain a role name as its first element. The second element is
-an optional hash reference. The hash reference can contain C<exclude>
-and C<alias> keys to control how methods are composed from the role.
+an optional hash reference. The hash reference can contain C<-excludes>
+and C<-alias> keys to control how methods are composed from the role.
 
 The return value is a new L<Moose::Meta::Role::Composite> that
 represents the combined roles.
@@ -888,13 +963,18 @@ Returns the list of methods required by the role.
 
 Returns true if the role requires the named method.
 
-=item B<< $metarole->add_required_methods(@names >>
+=item B<< $metarole->add_required_methods(@names) >>
 
-Adds the named methods to the roles list of required methods.
+Adds the named methods to the role's list of required methods.
 
 =item B<< $metarole->remove_required_methods(@names) >>
 
-Removes the named methods to the roles list of required methods.
+Removes the named methods from the role's list of required methods.
+
+=item B<< $metarole->add_conflicting_method(%params) >>
+
+Instantiate the parameters as a L<Moose::Meta::Role::Method::Conflicting>
+object, then add it to the required method list.
 
 =back