BEGIN-Lift

 view release on metacpan or  search on metacpan

lib/BEGIN/Lift.pm  view on Meta::CPAN

package BEGIN::Lift;
# ABSTRACT: Lift subroutine calls into the BEGIN phase

use strict;
use warnings;

our $VERSION;
our $AUTHORITY;

use Sub::Name   ();
use Devel::Hook ();

use Devel::CallParser;
use XSLoader;
BEGIN {
    $VERSION   = '0.07';
    $AUTHORITY = 'cpan:STEVAN';
    XSLoader::load( __PACKAGE__, $VERSION );
}

sub install {
    my ($pkg, $method, $handler) = @_;

    # need to force a new CV each time here
    # not entirely sure why, but I assume
    # that perl was trying to optimize things
    # which is not what I actually want.
    my $cv = eval 'sub {}';

    # now we need to install the stub
    # we just created, but first we need to
    # verify that we are the only ones using
    # the typeglob we are installing into.
    # This makes it easier/safer to delete
    # the stub before runtime.
    {
        no strict 'refs';
        die "Cannot install the lifted keyword ($method) into package ($pkg) when that typeglob (\*${pkg}::${method}) already exists"
            if exists ${"${pkg}::"}{$method};
        *{"${pkg}::${method}"} = $cv;
    }

    # give the handler a name so that
    # it shows up sensibly in stack
    # traces and the like ...
    Sub::Name::subname( "${pkg}::${method}", $handler );

    # install the keyword handler ...
    BEGIN::Lift::Util::install_keyword_handler(
        $cv, sub { $handler->( $_[0] ? $_[0]->() : () ) }
    );

    # clean things up ...
    Devel::Hook->unshift_UNITCHECK_hook(sub {
        no strict 'refs';
        # NOTE:
        # this is safe only because we
        # confirmed above that there was
        # no other use of this typeglob
        # and so it is ok to delete
        delete ${"${pkg}::"}{$method}
    });
}

1;

__END__

=pod

=head1 NAME

BEGIN::Lift - Lift subroutine calls into the BEGIN phase

=head1 SYNOPSIS

  package Cariboo;
  use strict;
  use warnings;

  use BEGIN::Lift;

  sub import {
      my $caller = caller;

      BEGIN::Lift::install(
          ($caller, 'extends') => sub {
              no strict 'refs';
              @{$caller . '::ISA'} = @_;
          }
      );
  }

  package Foo;
  use Cariboo;

  extends 'Bar';

  # functionally equivalent to ...
  # BEGIN { @ISA = ('Bar') }

=head1 DESCRIPTION

This module serves a very specific purpose, which is to provide a
mechanism through which we can "lift" a given subroutine to be
executed entirely within the C<BEGIN> phase of the Perl compiler
and to leave no trace of itself in the C<RUN> phase.

=head2 Modules loaded at runtime?

If a package that uses this module is loaded at runtime (perhaps
via the C<require> builtin), it will still work correctly (to the
best of my knowledge that is).



( run in 1.622 second using v1.01-cache-2.11-cpan-39bf76dae61 )