Role-Tiny
view release on metacpan or search on metacpan
lib/Role/Tiny.pm view on Meta::CPAN
sub _getglob { no strict 'refs'; \*{$_[0]} }
sub _getstash { no strict 'refs'; \%{"$_[0]::"} }
sub croak {
require Carp;
no warnings 'redefine';
*croak = \&Carp::croak;
goto &Carp::croak;
}
sub 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 ], 'Role::Tiny::__GUARD__');
local %^H if _WORK_AROUND_HINT_LEAKAGE;
require $file;
pop @$guard if _WORK_AROUND_BROKEN_MODULE_STATE;
return 1;
}
sub _require_module {
_load_module($_[1]);
}
sub _all_subs {
my ($me, $package) = @_;
my $stash = _getstash($package);
return {
map {;
no strict 'refs';
# this is an ugly hack to populate the scalar slot of any globs, to
# prevent perl from converting constants back into scalar refs in the
# stash when they are used (perl 5.12 - 5.18). scalar slots on their own
# aren't detectable through pure perl, so this seems like an acceptable
# compromise.
${"${package}::${_}"} = ${"${package}::${_}"}
if _CONSTANTS_DEFLATE;
$_ => \&{"${package}::${_}"}
}
grep exists &{"${package}::${_}"},
grep !/::\z/,
keys %$stash
};
}
sub import {
my $target = caller;
my $me = shift;
strict->import;
warnings->import;
$me->init_role($target, @_);
}
sub init_role {
my ($me, $target, @args) = @_;
my $non_methods = $me->_non_methods($target);
$me->_install_subs($target, @args);
$me->make_role($target);
$me->_mark_new_non_methods($target, $non_methods)
if $non_methods && %$non_methods;
return;
}
sub _mark_new_non_methods {
my ($me, $target, $old_non_methods) = @_;
my $non_methods = $INFO{$target}{non_methods};
my $subs = $me->_all_subs($target);
for my $sub (keys %$subs) {
if ( exists $old_non_methods->{$sub} && $non_methods->{$sub} != $subs->{$sub} ) {
$non_methods->{$sub} = $subs->{$sub};
}
}
return;
}
sub make_role {
my ($me, $target) = @_;
return if $me->is_role($target);
$INFO{$target}{is_role} = 1;
my $non_methods = $me->_all_subs($target);
delete @{$non_methods}{grep /\A\(/, keys %$non_methods};
$INFO{$target}{non_methods} = $non_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);
my %install = $me->_gen_subs($target);
*{_getglob("${target}::${_}")} = $install{$_}
for sort keys %install;
return;
}
sub _gen_subs {
my ($me, $target) = @_;
(
(map {;
( run in 0.633 second using v1.01-cache-2.11-cpan-5a3173703d6 )