Blame lib/Sub/Install.pm

Packit 1c5632
use strict;
Packit 1c5632
use warnings;
Packit 1c5632
package Sub::Install;
Packit 1c5632
# ABSTRACT: install subroutines into packages easily
Packit 1c5632
$Sub::Install::VERSION = '0.928';
Packit 1c5632
use Carp;
Packit 1c5632
use Scalar::Util ();
Packit 1c5632
Packit 1c5632
#pod =head1 SYNOPSIS
Packit 1c5632
#pod
Packit 1c5632
#pod   use Sub::Install;
Packit 1c5632
#pod
Packit 1c5632
#pod   Sub::Install::install_sub({
Packit 1c5632
#pod     code => sub { ... },
Packit 1c5632
#pod     into => $package,
Packit 1c5632
#pod     as   => $subname
Packit 1c5632
#pod   });
Packit 1c5632
#pod
Packit 1c5632
#pod =head1 DESCRIPTION
Packit 1c5632
#pod
Packit 1c5632
#pod This module makes it easy to install subroutines into packages without the
Packit 1c5632
#pod unsightly mess of C<no strict> or typeglobs lying about where just anyone can
Packit 1c5632
#pod see them.
Packit 1c5632
#pod
Packit 1c5632
#pod =func install_sub
Packit 1c5632
#pod
Packit 1c5632
#pod   Sub::Install::install_sub({
Packit 1c5632
#pod    code => \&subroutine,
Packit 1c5632
#pod    into => "Finance::Shady",
Packit 1c5632
#pod    as   => 'launder',
Packit 1c5632
#pod   });
Packit 1c5632
#pod
Packit 1c5632
#pod This routine installs a given code reference into a package as a normal
Packit 1c5632
#pod subroutine.  The above is equivalent to:
Packit 1c5632
#pod
Packit 1c5632
#pod   no strict 'refs';
Packit 1c5632
#pod   *{"Finance::Shady" . '::' . "launder"} = \&subroutine;
Packit 1c5632
#pod
Packit 1c5632
#pod If C<into> is not given, the sub is installed into the calling package.
Packit 1c5632
#pod
Packit 1c5632
#pod If C is not a code reference, it is looked for as an existing sub in the
Packit 1c5632
#pod package named in the C<from> parameter.  If C<from> is not given, it will look
Packit 1c5632
#pod in the calling package.
Packit 1c5632
#pod
Packit 1c5632
#pod If C<as> is not given, and if C is a name, C<as> will default to C.
Packit 1c5632
#pod If C<as> is not given, but if C is a code ref, Sub::Install will try to
Packit 1c5632
#pod find the name of the given code ref and use that as C<as>.
Packit 1c5632
#pod
Packit 1c5632
#pod That means that this code:
Packit 1c5632
#pod
Packit 1c5632
#pod   Sub::Install::install_sub({
Packit 1c5632
#pod     code => 'twitch',
Packit 1c5632
#pod     from => 'Person::InPain',
Packit 1c5632
#pod     into => 'Person::Teenager',
Packit 1c5632
#pod     as   => 'dance',
Packit 1c5632
#pod   });
Packit 1c5632
#pod
Packit 1c5632
#pod is the same as:
Packit 1c5632
#pod
Packit 1c5632
#pod   package Person::Teenager;
Packit 1c5632
#pod
Packit 1c5632
#pod   Sub::Install::install_sub({
Packit 1c5632
#pod     code => Person::InPain->can('twitch'),
Packit 1c5632
#pod     as   => 'dance',
Packit 1c5632
#pod   });
Packit 1c5632
#pod
Packit 1c5632
#pod =func reinstall_sub
Packit 1c5632
#pod
Packit 1c5632
#pod This routine behaves exactly like C<L</install_sub>>, but does not emit a
Packit 1c5632
#pod warning if warnings are on and the destination is already defined.
Packit 1c5632
#pod
Packit 1c5632
#pod =cut
Packit 1c5632
Packit 1c5632
sub _name_of_code {
Packit 1c5632
  my ($code) = @_;
Packit 1c5632
  require B;
Packit 1c5632
  my $name = B::svref_2object($code)->GV->NAME;
Packit 1c5632
  return $name unless $name =~ /\A__ANON__/;
Packit 1c5632
  return;
Packit 1c5632
}
Packit 1c5632
Packit 1c5632
# See also Params::Util, to which this code was donated.
Packit 1c5632
sub _CODELIKE {
Packit 1c5632
  (Scalar::Util::reftype($_[0])||'') eq 'CODE'
Packit 1c5632
  || Scalar::Util::blessed($_[0])
Packit 1c5632
  && (overload::Method($_[0],'&{}') ? $_[0] : undef);
Packit 1c5632
}
Packit 1c5632
Packit 1c5632
# do the heavy lifting
Packit 1c5632
sub _build_public_installer {
Packit 1c5632
  my ($installer) = @_;
Packit 1c5632
Packit 1c5632
  sub {
Packit 1c5632
    my ($arg) = @_;
Packit 1c5632
    my ($calling_pkg) = caller(0);
Packit 1c5632
Packit 1c5632
    # I'd rather use ||= but I'm whoring for Devel::Cover.
Packit 1c5632
    for (qw(into from)) { $arg->{$_} = $calling_pkg unless $arg->{$_} }
Packit 1c5632
Packit 1c5632
    # This is the only absolutely required argument, in many cases.
Packit 1c5632
    Carp::croak "named argument 'code' is not optional" unless $arg->{code};
Packit 1c5632
Packit 1c5632
    if (_CODELIKE($arg->{code})) {
Packit 1c5632
      $arg->{as} ||= _name_of_code($arg->{code});
Packit 1c5632
    } else {
Packit 1c5632
      Carp::croak
Packit 1c5632
        "couldn't find subroutine named $arg->{code} in package $arg->{from}"
Packit 1c5632
        unless my $code = $arg->{from}->can($arg->{code});
Packit 1c5632
Packit 1c5632
      $arg->{as}   = $arg->{code} unless $arg->{as};
Packit 1c5632
      $arg->{code} = $code;
Packit 1c5632
    }
Packit 1c5632
Packit 1c5632
    Carp::croak "couldn't determine name under which to install subroutine"
Packit 1c5632
      unless $arg->{as};
Packit 1c5632
Packit 1c5632
    $installer->(@$arg{qw(into as code) });
Packit 1c5632
  }
Packit 1c5632
}
Packit 1c5632
Packit 1c5632
# do the ugly work
Packit 1c5632
Packit 1c5632
my $_misc_warn_re;
Packit 1c5632
my $_redef_warn_re;
Packit 1c5632
BEGIN {
Packit 1c5632
  $_misc_warn_re = qr/
Packit 1c5632
    Prototype\ mismatch:\ sub\ .+?  |
Packit 1c5632
    Constant subroutine .+? redefined
Packit 1c5632
  /x;
Packit 1c5632
  $_redef_warn_re = qr/Subroutine\ .+?\ redefined/x;
Packit 1c5632
}
Packit 1c5632
Packit 1c5632
my $eow_re;
Packit 1c5632
BEGIN { $eow_re = qr/ at .+? line \d+\.\Z/ };
Packit 1c5632
Packit 1c5632
sub _do_with_warn {
Packit 1c5632
  my ($arg) = @_;
Packit 1c5632
  my $code = delete $arg->{code};
Packit 1c5632
  my $wants_code = sub {
Packit 1c5632
    my $code = shift;
Packit 1c5632
    sub {
Packit 1c5632
      my $warn = $SIG{__WARN__} ? $SIG{__WARN__} : sub { warn @_ }; ## no critic
Packit 1c5632
      local $SIG{__WARN__} = sub {
Packit 1c5632
        my ($error) = @_;
Packit 1c5632
        for (@{ $arg->{suppress} }) {
Packit 1c5632
            return if $error =~ $_;
Packit 1c5632
        }
Packit 1c5632
        for (@{ $arg->{croak} }) {
Packit 1c5632
          if (my ($base_error) = $error =~ /\A($_) $eow_re/x) {
Packit 1c5632
            Carp::croak $base_error;
Packit 1c5632
          }
Packit 1c5632
        }
Packit 1c5632
        for (@{ $arg->{carp} }) {
Packit 1c5632
          if (my ($base_error) = $error =~ /\A($_) $eow_re/x) {
Packit 1c5632
            return $warn->(Carp::shortmess $base_error);
Packit 1c5632
          }
Packit 1c5632
        }
Packit 1c5632
        ($arg->{default} || $warn)->($error);
Packit 1c5632
      };
Packit 1c5632
      $code->(@_);
Packit 1c5632
    };
Packit 1c5632
  };
Packit 1c5632
  return $wants_code->($code) if $code;
Packit 1c5632
  return $wants_code;
Packit 1c5632
}
Packit 1c5632
Packit 1c5632
sub _installer {
Packit 1c5632
  sub {
Packit 1c5632
    my ($pkg, $name, $code) = @_;
Packit 1c5632
    no strict 'refs'; ## no critic ProhibitNoStrict
Packit 1c5632
    *{"$pkg\::$name"} = $code;
Packit 1c5632
    return $code;
Packit 1c5632
  }
Packit 1c5632
}
Packit 1c5632
Packit 1c5632
BEGIN {
Packit 1c5632
  *_ignore_warnings = _do_with_warn({
Packit 1c5632
    carp => [ $_misc_warn_re, $_redef_warn_re ]
Packit 1c5632
  });
Packit 1c5632
Packit 1c5632
  *install_sub = _build_public_installer(_ignore_warnings(_installer));
Packit 1c5632
Packit 1c5632
  *_carp_warnings =  _do_with_warn({
Packit 1c5632
    carp     => [ $_misc_warn_re ],
Packit 1c5632
    suppress => [ $_redef_warn_re ],
Packit 1c5632
  });
Packit 1c5632
Packit 1c5632
  *reinstall_sub = _build_public_installer(_carp_warnings(_installer));
Packit 1c5632
Packit 1c5632
  *_install_fatal = _do_with_warn({
Packit 1c5632
    code     => _installer,
Packit 1c5632
    croak    => [ $_redef_warn_re ],
Packit 1c5632
  });
Packit 1c5632
}
Packit 1c5632
Packit 1c5632
#pod =func install_installers
Packit 1c5632
#pod
Packit 1c5632
#pod This routine is provided to allow Sub::Install compatibility with
Packit 1c5632
#pod Sub::Installer.  It installs C<install_sub> and C<reinstall_sub> methods into
Packit 1c5632
#pod the package named by its argument.
Packit 1c5632
#pod
Packit 1c5632
#pod  Sub::Install::install_installers('Code::Builder'); # just for us, please
Packit 1c5632
#pod  Code::Builder->install_sub({ name => $code_ref });
Packit 1c5632
#pod
Packit 1c5632
#pod  Sub::Install::install_installers('UNIVERSAL'); # feeling lucky, punk?
Packit 1c5632
#pod  Anything::At::All->install_sub({ name => $code_ref });
Packit 1c5632
#pod
Packit 1c5632
#pod The installed installers are similar, but not identical, to those provided by
Packit 1c5632
#pod Sub::Installer.  They accept a single hash as an argument.  The key/value pairs
Packit 1c5632
#pod are used as the C<as> and C parameters to the C<install_sub> routine
Packit 1c5632
#pod detailed above.  The package name on which the method is called is used as the
Packit 1c5632
#pod C<into> parameter.
Packit 1c5632
#pod
Packit 1c5632
#pod Unlike Sub::Installer's C<install_sub> will not eval strings into code, but
Packit 1c5632
#pod will look for named code in the calling package.
Packit 1c5632
#pod
Packit 1c5632
#pod =cut
Packit 1c5632
Packit 1c5632
sub install_installers {
Packit 1c5632
  my ($into) = @_;
Packit 1c5632
Packit 1c5632
  for my $method (qw(install_sub reinstall_sub)) {
Packit 1c5632
    my $code = sub {
Packit 1c5632
      my ($package, $subs) = @_;
Packit 1c5632
      my ($caller) = caller(0);
Packit 1c5632
      my $return;
Packit 1c5632
      for (my ($name, $sub) = %$subs) {
Packit 1c5632
        $return = Sub::Install->can($method)->({
Packit 1c5632
          code => $sub,
Packit 1c5632
          from => $caller,
Packit 1c5632
          into => $package,
Packit 1c5632
          as   => $name
Packit 1c5632
        });
Packit 1c5632
      }
Packit 1c5632
      return $return;
Packit 1c5632
    };
Packit 1c5632
    install_sub({ code => $code, into => $into, as => $method });
Packit 1c5632
  }
Packit 1c5632
}
Packit 1c5632
Packit 1c5632
#pod =head1 EXPORTS
Packit 1c5632
#pod
Packit 1c5632
#pod Sub::Install exports C<install_sub> and C<reinstall_sub> only if they are
Packit 1c5632
#pod requested.
Packit 1c5632
#pod
Packit 1c5632
#pod =head2 exporter
Packit 1c5632
#pod
Packit 1c5632
#pod Sub::Install has a never-exported subroutine called C<exporter>, which is used
Packit 1c5632
#pod to implement its C<import> routine.  It takes a hashref of named arguments,
Packit 1c5632
#pod only one of which is currently recognize: C<exports>.  This must be an arrayref
Packit 1c5632
#pod of subroutines to offer for export.
Packit 1c5632
#pod
Packit 1c5632
#pod This routine is mainly for Sub::Install's own consumption.  Instead, consider
Packit 1c5632
#pod L<Sub::Exporter>.
Packit 1c5632
#pod
Packit 1c5632
#pod =cut
Packit 1c5632
Packit 1c5632
sub exporter {
Packit 1c5632
  my ($arg) = @_;
Packit 1c5632
Packit 1c5632
  my %is_exported = map { $_ => undef } @{ $arg->{exports} };
Packit 1c5632
Packit 1c5632
  sub {
Packit 1c5632
    my $class = shift;
Packit 1c5632
    my $target = caller;
Packit 1c5632
    for (@_) {
Packit 1c5632
      Carp::croak "'$_' is not exported by $class" if !exists $is_exported{$_};
Packit 1c5632
      install_sub({ code => $_, from => $class, into => $target });
Packit 1c5632
    }
Packit 1c5632
  }
Packit 1c5632
}
Packit 1c5632
Packit 1c5632
BEGIN { *import = exporter({ exports => [ qw(install_sub reinstall_sub) ] }); }
Packit 1c5632
Packit 1c5632
#pod =head1 SEE ALSO
Packit 1c5632
#pod
Packit 1c5632
#pod =over
Packit 1c5632
#pod
Packit 1c5632
#pod =item L<Sub::Installer>
Packit 1c5632
#pod
Packit 1c5632
#pod This module is (obviously) a reaction to Damian Conway's Sub::Installer, which
Packit 1c5632
#pod does the same thing, but does it by getting its greasy fingers all over
Packit 1c5632
#pod UNIVERSAL.  I was really happy about the idea of making the installation of
Packit 1c5632
#pod coderefs less ugly, but I couldn't bring myself to replace the ugliness of
Packit 1c5632
#pod typeglobs and loosened strictures with the ugliness of UNIVERSAL methods.
Packit 1c5632
#pod
Packit 1c5632
#pod =item L<Sub::Exporter>
Packit 1c5632
#pod
Packit 1c5632
#pod This is a complete Exporter.pm replacement, built atop Sub::Install.
Packit 1c5632
#pod
Packit 1c5632
#pod =back
Packit 1c5632
#pod
Packit 1c5632
#pod =head1 EXTRA CREDITS
Packit 1c5632
#pod
Packit 1c5632
#pod Several of the tests are adapted from tests that shipped with Damian Conway's
Packit 1c5632
#pod Sub-Installer distribution.
Packit 1c5632
#pod
Packit 1c5632
#pod =cut
Packit 1c5632
Packit 1c5632
1;
Packit 1c5632
Packit 1c5632
__END__
Packit 1c5632
Packit 1c5632
=pod
Packit 1c5632
Packit 1c5632
=encoding UTF-8
Packit 1c5632
Packit 1c5632
=head1 NAME
Packit 1c5632
Packit 1c5632
Sub::Install - install subroutines into packages easily
Packit 1c5632
Packit 1c5632
=head1 VERSION
Packit 1c5632
Packit 1c5632
version 0.928
Packit 1c5632
Packit 1c5632
=head1 SYNOPSIS
Packit 1c5632
Packit 1c5632
  use Sub::Install;
Packit 1c5632
Packit 1c5632
  Sub::Install::install_sub({
Packit 1c5632
    code => sub { ... },
Packit 1c5632
    into => $package,
Packit 1c5632
    as   => $subname
Packit 1c5632
  });
Packit 1c5632
Packit 1c5632
=head1 DESCRIPTION
Packit 1c5632
Packit 1c5632
This module makes it easy to install subroutines into packages without the
Packit 1c5632
unsightly mess of C<no strict> or typeglobs lying about where just anyone can
Packit 1c5632
see them.
Packit 1c5632
Packit 1c5632
=head1 FUNCTIONS
Packit 1c5632
Packit 1c5632
=head2 install_sub
Packit 1c5632
Packit 1c5632
  Sub::Install::install_sub({
Packit 1c5632
   code => \&subroutine,
Packit 1c5632
   into => "Finance::Shady",
Packit 1c5632
   as   => 'launder',
Packit 1c5632
  });
Packit 1c5632
Packit 1c5632
This routine installs a given code reference into a package as a normal
Packit 1c5632
subroutine.  The above is equivalent to:
Packit 1c5632
Packit 1c5632
  no strict 'refs';
Packit 1c5632
  *{"Finance::Shady" . '::' . "launder"} = \&subroutine;
Packit 1c5632
Packit 1c5632
If C<into> is not given, the sub is installed into the calling package.
Packit 1c5632
Packit 1c5632
If C is not a code reference, it is looked for as an existing sub in the
Packit 1c5632
package named in the C<from> parameter.  If C<from> is not given, it will look
Packit 1c5632
in the calling package.
Packit 1c5632
Packit 1c5632
If C<as> is not given, and if C is a name, C<as> will default to C.
Packit 1c5632
If C<as> is not given, but if C is a code ref, Sub::Install will try to
Packit 1c5632
find the name of the given code ref and use that as C<as>.
Packit 1c5632
Packit 1c5632
That means that this code:
Packit 1c5632
Packit 1c5632
  Sub::Install::install_sub({
Packit 1c5632
    code => 'twitch',
Packit 1c5632
    from => 'Person::InPain',
Packit 1c5632
    into => 'Person::Teenager',
Packit 1c5632
    as   => 'dance',
Packit 1c5632
  });
Packit 1c5632
Packit 1c5632
is the same as:
Packit 1c5632
Packit 1c5632
  package Person::Teenager;
Packit 1c5632
Packit 1c5632
  Sub::Install::install_sub({
Packit 1c5632
    code => Person::InPain->can('twitch'),
Packit 1c5632
    as   => 'dance',
Packit 1c5632
  });
Packit 1c5632
Packit 1c5632
=head2 reinstall_sub
Packit 1c5632
Packit 1c5632
This routine behaves exactly like C<L</install_sub>>, but does not emit a
Packit 1c5632
warning if warnings are on and the destination is already defined.
Packit 1c5632
Packit 1c5632
=head2 install_installers
Packit 1c5632
Packit 1c5632
This routine is provided to allow Sub::Install compatibility with
Packit 1c5632
Sub::Installer.  It installs C<install_sub> and C<reinstall_sub> methods into
Packit 1c5632
the package named by its argument.
Packit 1c5632
Packit 1c5632
 Sub::Install::install_installers('Code::Builder'); # just for us, please
Packit 1c5632
 Code::Builder->install_sub({ name => $code_ref });
Packit 1c5632
Packit 1c5632
 Sub::Install::install_installers('UNIVERSAL'); # feeling lucky, punk?
Packit 1c5632
 Anything::At::All->install_sub({ name => $code_ref });
Packit 1c5632
Packit 1c5632
The installed installers are similar, but not identical, to those provided by
Packit 1c5632
Sub::Installer.  They accept a single hash as an argument.  The key/value pairs
Packit 1c5632
are used as the C<as> and C parameters to the C<install_sub> routine
Packit 1c5632
detailed above.  The package name on which the method is called is used as the
Packit 1c5632
C<into> parameter.
Packit 1c5632
Packit 1c5632
Unlike Sub::Installer's C<install_sub> will not eval strings into code, but
Packit 1c5632
will look for named code in the calling package.
Packit 1c5632
Packit 1c5632
=head1 EXPORTS
Packit 1c5632
Packit 1c5632
Sub::Install exports C<install_sub> and C<reinstall_sub> only if they are
Packit 1c5632
requested.
Packit 1c5632
Packit 1c5632
=head2 exporter
Packit 1c5632
Packit 1c5632
Sub::Install has a never-exported subroutine called C<exporter>, which is used
Packit 1c5632
to implement its C<import> routine.  It takes a hashref of named arguments,
Packit 1c5632
only one of which is currently recognize: C<exports>.  This must be an arrayref
Packit 1c5632
of subroutines to offer for export.
Packit 1c5632
Packit 1c5632
This routine is mainly for Sub::Install's own consumption.  Instead, consider
Packit 1c5632
L<Sub::Exporter>.
Packit 1c5632
Packit 1c5632
=head1 SEE ALSO
Packit 1c5632
Packit 1c5632
=over
Packit 1c5632
Packit 1c5632
=item L<Sub::Installer>
Packit 1c5632
Packit 1c5632
This module is (obviously) a reaction to Damian Conway's Sub::Installer, which
Packit 1c5632
does the same thing, but does it by getting its greasy fingers all over
Packit 1c5632
UNIVERSAL.  I was really happy about the idea of making the installation of
Packit 1c5632
coderefs less ugly, but I couldn't bring myself to replace the ugliness of
Packit 1c5632
typeglobs and loosened strictures with the ugliness of UNIVERSAL methods.
Packit 1c5632
Packit 1c5632
=item L<Sub::Exporter>
Packit 1c5632
Packit 1c5632
This is a complete Exporter.pm replacement, built atop Sub::Install.
Packit 1c5632
Packit 1c5632
=back
Packit 1c5632
Packit 1c5632
=head1 EXTRA CREDITS
Packit 1c5632
Packit 1c5632
Several of the tests are adapted from tests that shipped with Damian Conway's
Packit 1c5632
Sub-Installer distribution.
Packit 1c5632
Packit 1c5632
=head1 AUTHOR
Packit 1c5632
Packit 1c5632
Ricardo SIGNES <rjbs@cpan.org>
Packit 1c5632
Packit 1c5632
=head1 COPYRIGHT AND LICENSE
Packit 1c5632
Packit 1c5632
This software is copyright (c) 2005 by Ricardo SIGNES.
Packit 1c5632
Packit 1c5632
This is free software; you can redistribute it and/or modify it under
Packit 1c5632
the same terms as the Perl 5 programming language system itself.
Packit 1c5632
Packit 1c5632
=cut