File Coverage

blib/lib/Sub/WhenBodied.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Sub::WhenBodied - delay action until subroutine acquires body
4              
5             =head1 SYNOPSIS
6              
7             use Sub::WhenBodied qw(when_sub_bodied);
8              
9             when_sub_bodied($sub, sub { mutate_sub_foo($_[0], ...) });
10              
11             =head1 DESCRIPTION
12              
13             This module provides a facility to delay an action on a subroutine until
14             the subroutine's body (the code that will be run when the subroutine
15             is called) has been attached to the subroutine object. This is mainly
16             useful in implementing subroutine attributes, where the implementation
17             needs to operate on the subroutine's body.
18              
19             This facility is required due to an oddity of how Perl constructs
20             Perl-language subroutines. A subroutine object is initially created
21             with no body, and then the body is later attached. Prior to Perl 5.15.4,
22             attribute handlers are executed before the body is attached, so see it in
23             that intermediate state. (From Perl 5.15.4 onwards, attribute handlers
24             are executed after the body is attached.) It is otherwise unusual to
25             see the subroutine in that intermediate state. If the implementation
26             of an attribute can only be completed after the body is attached, this
27             module is the way to schedule the implementation.
28              
29             =cut
30              
31             package Sub::WhenBodied;
32              
33 1     1   14853 { use 5.008; }
  1         2  
  1         29  
34 1     1   4 use warnings;
  1         1  
  1         24  
35 1     1   10 use strict;
  1         1  
  1         40  
36              
37             our $VERSION = "0.000";
38              
39 1     1   402 use parent "Exporter";
  1         212  
  1         3  
40             our @EXPORT_OK = qw(when_sub_bodied);
41              
42             require XSLoader;
43             XSLoader::load(__PACKAGE__, $VERSION);
44              
45             =head1 FUNCTIONS
46              
47             =over
48              
49             =item when_sub_bodied(SUB, ACTION)
50              
51             I must be a reference to a subroutine. This function queues
52             a modification of the subroutine, to occur when the subroutine has
53             acquired a body. I must be a reference to a function, which will
54             eventually be called, with one argument, a reference to the subroutine to
55             act on. The subroutine passed to I is not necessarily the same
56             object as the original I: some subroutine construction sequences
57             cause the partially-built subroutine to move from one object to another
58             part way through, and a pending action will move with it.
59              
60             If this function is called when I is in the half-constructed state,
61             with body not yet attached, then I is added to a per-subroutine
62             queue. Shortly after a body is attached to I, the queued actions
63             are performed.
64              
65             If this function is called when I already has a body, the action
66             will be performed immediately, or nearly so. Actions are always
67             performed sequentially, in the order in which they were queued, so if
68             an action is requested while another action is already executing then
69             the newly-requested action will have to wait until the executing one
70             has finished.
71              
72             If a subroutine with pending actions is replaced, in the same subroutine
73             object, by a new subroutine, then the queue of pending actions is
74             discarded. This occurs in the case of a so-called "forward declaration",
75             such as "C". The declaration creates a subroutine with
76             no body, to influence compilation of calls to the subroutine, and it
77             is intended that the empty subroutine will later be replaced by a full
78             subroutine which has a body.
79              
80             =back
81              
82             =head1 BUGS
83              
84             The code is an ugly hack. Details of its behaviour may change in future
85             versions of this module, if better ways of achieving the desired effect
86             are found.
87              
88             Before Perl 5.10, C has a particular problem with
89             redefining subroutines. A subroutine redefinition, including if the
90             previous definition had no body (a pre-declaration), is the situation
91             that causes a partially-built subroutine to move from one subroutine
92             object to another. On pre-5.10 Perls, it is impossible to locate the
93             destination object at the critical point in this process, and as a result
94             any pending actions are lost.
95              
96             =head1 SEE ALSO
97              
98             L
99              
100             =head1 AUTHOR
101              
102             Andrew Main (Zefram)
103              
104             =head1 COPYRIGHT
105              
106             Copyright (C) 2009, 2010, 2011, 2013, 2015
107             Andrew Main (Zefram)
108              
109             =head1 LICENSE
110              
111             This module is free software; you can redistribute it and/or modify it
112             under the same terms as Perl itself.
113              
114             =cut
115              
116             1;