use Scalar::Util 'blessed';
use Carp 'confess';
+use Sub::Name 'subname';
+use Devel::GlobalDestruction 'in_global_destruction';
-our $VERSION = '0.76';
+our $VERSION = '0.87';
$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';
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',
}
},
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',
}
},
{
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',
}
$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) = @_;
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 {
$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
$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 {
my $full_method_name = ($self->name . '::' . $method_name);
$self->add_package_symbol(
{ sigil => '&', type => 'CODE', name => $method_name },
- Class::MOP::subname($full_method_name => $body)
+ subname($full_method_name => $body)
);
$self->update_package_cache_flag; # still valid, since we just added the method to the map, and if it was invalid before that then get_method_map updated it
(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 {
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);
return $c;
}
+sub _role_for_combination {
+ my ($self, $params) = @_;
+ return $self;
+}
+
sub create {
my ( $role, $package_name, %options ) = @_;
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/;
# has 'roles' => (
# metaclass => 'Collection::Array',
# reader => 'get_roles',
-# isa => 'ArrayRef[Moose::Meta::Roles]',
+# isa => 'ArrayRef[Moose::Meta::Role]',
# default => sub { [] },
# provides => {
# 'push' => 'add_role',
# 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',
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>
+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
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