Jojo-Role
view release on metacpan or search on metacpan
lib/Jojo/Role/Tiny.pm view on Meta::CPAN
our $VERSION = '2.000006';
$VERSION =~ tr/_//d;
# Aliasing of Role::Tiny symbols
BEGIN {
*INFO = \%Role::Tiny::INFO;
*APPLIED_TO = \%Role::Tiny::APPLIED_TO;
*COMPOSED = \%Role::Tiny::COMPOSED;
*COMPOSITE_INFO = \%Role::Tiny::COMPOSITE_INFO;
*ON_ROLE_CREATE = \@Role::Tiny::ON_ROLE_CREATE;
}
our %INFO;
our %APPLIED_TO;
our %COMPOSED;
our %COMPOSITE_INFO;
our @ON_ROLE_CREATE;
# Module state workaround totally stolen from Zefram's Module::Runtime.
BEGIN {
*_WORK_AROUND_BROKEN_MODULE_STATE = "$]" < 5.009 ? sub(){1} : sub(){0};
*_WORK_AROUND_HINT_LEAKAGE
= "$]" < 5.011 && !("$]" >= 5.009004 && "$]" < 5.010001)
? sub(){1} : sub(){0};
*_MRO_MODULE = "$]" < 5.010 ? sub(){"MRO/Compat.pm"} : sub(){"mro.pm"};
}
sub croak {
require Carp;
no warnings 'redefine';
*croak = \&Carp::croak;
goto &Carp::croak;
}
sub Jojo::Role::Tiny::__GUARD__::DESTROY {
delete $INC{$_[0]->[0]} if @{$_[0]};
}
sub _load_module {
my ($module) = @_;
(my $file = "$module.pm") =~ s{::}{/}g;
return 1
if $INC{$file};
# can't just ->can('can') because a sub-package Foo::Bar::Baz
# creates a 'Baz::' key in Foo::Bar's symbol table
return 1
if grep !/::\z/, keys %{_getstash($module)};
my $guard = _WORK_AROUND_BROKEN_MODULE_STATE
&& bless([ $file ], 'Jojo::Role::Tiny::__GUARD__');
local %^H if _WORK_AROUND_HINT_LEAKAGE;
require $file;
pop @$guard if _WORK_AROUND_BROKEN_MODULE_STATE;
return 1;
}
sub import {
my $target = caller;
my $me = shift;
strict->import;
warnings->import;
$me->_install_subs($target);
$me->make_role($target);
}
sub make_role {
my ($me, $target) = @_;
return if $me->is_role($target); # already exported into this package
$INFO{$target}{is_role} = 1;
# get symbol table reference
my $stash = _getstash($target);
# grab all *non-constant* (stash slot is not a scalarref) subs present
# in the symbol table and store their refaddrs (no need to forcibly
# inflate constant subs into real subs) with a map to the coderefs in
# case of copying or re-use
my @not_methods = map +(ref $_ eq 'CODE' ? $_ : ref $_ ? () : *$_{CODE}||()), values %$stash;
@{$INFO{$target}{not_methods}={}}{@not_methods} = @not_methods;
# a role does itself
$APPLIED_TO{$target} = { $target => undef };
foreach my $hook (@ON_ROLE_CREATE) {
$hook->($target);
}
}
sub _install_subs {
my ($me, $target) = @_;
return if $me->is_role($target);
# install before/after/around subs
foreach my $type (qw(before after around)) {
*{_getglob "${target}::${type}"} = sub {
push @{$INFO{$target}{modifiers}||=[]}, [ $type => @_ ];
return;
};
}
*{_getglob "${target}::requires"} = sub {
push @{$INFO{$target}{requires}||=[]}, @_;
return;
};
*{_getglob "${target}::with"} = sub {
$me->apply_roles_to_package($target, @_);
return;
};
}
sub role_application_steps {
qw(_install_methods _check_requires _install_modifiers _copy_applied_list);
}
sub apply_single_role_to_package {
my ($me, $to, $role) = @_;
_load_module($role);
croak "This is apply_role_to_package" if ref($to);
croak "${role} is not a Role::Tiny" unless $me->is_role($role);
foreach my $step ($me->role_application_steps) {
$me->$step($to, $role);
}
}
( run in 2.035 seconds using v1.01-cache-2.11-cpan-ad19def0cd9 )