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 )