Class-Mite
view release on metacpan or search on metacpan
lib/Role.pm view on Meta::CPAN
package Role;
use strict;
use warnings;
use version;
our $VERSION = qv('v0.1.1');
our $AUTHORITY = 'cpan:MANWAR';
our %REQUIRED_METHODS;
our %IS_ROLE;
our %EXCLUDED_ROLES;
our %APPLIED_ROLES;
our %METHOD_ALIASES;
our %ROLE_ATTRIBUTES;
our %METHOD_ORIGIN_CACHE;
our %ROLE_LOAD_CACHE;
our %CAN_HANDLE_ATTR_CACHE;
our %ROLE_METHODS_CACHE;
# Precomputed skip patterns
my %SKIP_METHODS = map { $_ => 1 } qw(
BEGIN END import DESTROY new requires
excludes IS_ROLE with has does
AUTOLOAD VERSION AUTHORITY INC
);
sub import {
my ($class, @args) = @_;
my $caller = caller;
no strict 'refs';
$IS_ROLE{$caller} = 1;
if (@args == 0) {
$REQUIRED_METHODS{$caller} = [];
*{"${caller}::requires"} = \&requires;
*{"${caller}::excludes"} = \&excludes;
*{"${caller}::has"} = \&_role_has;
} else {
_setup_role_application($caller, @args);
}
strict->import;
warnings->import;
_export_with($caller);
}
sub with {
my (@roles) = @_;
my $caller = caller;
# Called inside a ROLE
if ($IS_ROLE{$caller}) {
my ($clean_roles_ref, $aliases_by_role)
= _process_role_arguments(@roles);
$METHOD_ALIASES{$caller} = $aliases_by_role;
foreach my $role (@$clean_roles_ref) {
_ensure_role_loaded($role);
push @{ $APPLIED_ROLES{$caller} ||= [] }, $role;
# Merge required methods
if (my $req = $REQUIRED_METHODS{$role}) {
push @{ $REQUIRED_METHODS{$caller} ||= [] }, @$req;
}
}
return;
}
apply_role($caller, @roles);
}
sub requires {
my (@methods) = @_;
my $caller = caller;
$REQUIRED_METHODS{$caller} = [] unless exists $REQUIRED_METHODS{$caller};
push @{$REQUIRED_METHODS{$caller}}, @methods;
}
sub excludes {
my (@excluded_roles) = @_;
my $caller = caller;
$EXCLUDED_ROLES{$caller} = [] unless exists $EXCLUDED_ROLES{$caller};
push @{$EXCLUDED_ROLES{$caller}}, @excluded_roles;
}
sub apply_role {
my ($class, @roles) = @_;
my $target_class = ref($class) ? ref($class) : $class;
my ($clean_roles_ref, $aliases_by_role) =
_process_role_arguments(@roles);
$METHOD_ALIASES{$target_class} = {
%{$METHOD_ALIASES{$target_class} || {}},
%$aliases_by_role
};
foreach my $role (@$clean_roles_ref) {
_apply_single_role($target_class, $role);
}
_add_does_method($target_class);
( run in 0.561 second using v1.01-cache-2.11-cpan-71847e10f99 )