File Coverage

blib/lib/BEGIN/Lift.pm
Criterion Covered Total %
statement 41 41 100.0
branch 6 6 100.0
condition n/a
subroutine 12 12 100.0
pod 1 1 100.0
total 60 60 100.0


line stmt bran cond sub pod time code
1             package BEGIN::Lift;
2             # ABSTRACT: Lift subroutine calls into the BEGIN phase
3              
4 9     9   120533 use strict;
  9         11  
  9         201  
5 9     9   26 use warnings;
  9         7  
  9         270  
6              
7             our $VERSION;
8             our $AUTHORITY;
9              
10 9     9   3461 use Sub::Name ();
  9         3440  
  9         163  
11 9     9   3503 use B::CompilerPhase::Hook ();
  9         3919  
  9         127  
12              
13 9     9   3537 use Devel::CallParser;
  9         18058  
  9         374  
14 9     9   36 use XSLoader;
  9         10  
  9         429  
15             BEGIN {
16 9     9   13 $VERSION = '0.04';
17 9         10 $AUTHORITY = 'cpan:STEVAN';
18 9         3244 XSLoader::load( __PACKAGE__, $VERSION );
19             }
20              
21             sub install {
22 8     8 1 15683 my ($pkg, $method, $handler) = @_;
23              
24             # It does not make any sense to create
25             # something that is meant to run in the
26             # BEGIN phase *after* that phase is done
27             # so catch this and error ...
28 8 100       45 die 'Lifted keywords must be created during BEGIN time, not (' . ${^GLOBAL_PHASE}. ')'
29             unless ${^GLOBAL_PHASE} eq 'START';
30              
31             # need to force a new CV each time here
32             # not entirely sure why, but I assume
33             # that perl was trying to optimize things
34             # which is not what I actually want.
35 7         470 my $cv = eval 'sub {}';
36              
37             # now we need to install the stub
38             # we just created, but first we need to
39             # verify that we are the only ones using
40             # the typeglob we are installing into.
41             # This makes it easier/safer to delete
42             # the stub before runtime.
43             {
44 9     9   52 no strict 'refs';
  9         8  
  9         1195  
  7         8  
45             die "Cannot install the lifted keyword ($method) into package ($pkg) when that typeglob (\*${pkg}::${method}) already exists"
46 7 100       6 if exists ${"${pkg}::"}{$method};
  7         41  
47 6         5 *{"${pkg}::${method}"} = $cv;
  6         38  
48             }
49              
50             # give the handler a name so that
51             # it shows up sensibly in stack
52             # traces and the like ...
53 6         58 Sub::Name::subname( "${pkg}::${method}", $handler );
54              
55             # install the keyword handler ...
56             BEGIN::Lift::Util::install_keyword_handler(
57 9 100   9   2087 $cv, sub { $handler->( $_[0] ? $_[0]->() : () ) }
58 6         28 );
59              
60             # clean things up ...
61             B::CompilerPhase::Hook::enqueue_UNITCHECK {
62 9     9   32 no strict 'refs';
  9         11  
  9         648  
63             # NOTE:
64             # this is safe only because we
65             # confirmed above that there was
66             # no other use of this typeglob
67             # and so it is ok to delete
68 6     6   5824 delete ${"${pkg}::"}{$method}
  6         3299  
69 6         430 };
70             }
71              
72             1;
73              
74             __END__