File Coverage

blib/lib/Hook/AfterRuntime.pm
Criterion Covered Total %
statement 25 25 100.0
branch n/a
condition n/a
subroutine 9 9 100.0
pod 0 4 0.0
total 34 38 89.4


line stmt bran cond sub pod time code
1             package Hook::AfterRuntime;
2 3     3   79463 use strict;
  3         9  
  3         115  
3 3     3   16 use warnings;
  3         13  
  3         78  
4              
5 3     3   2660 use B::Hooks::Parser;
  3         12031  
  3         100  
6 3     3   21 use base 'Exporter';
  3         6  
  3         1428  
7              
8             our $VERSION = '0.005';
9             our @EXPORT = qw/after_runtime/;
10             our @IDS;
11             our $HOOK_ID = 'AAAAAAAA';
12              
13             sub get_id {
14 3     3 0 7 my $code = shift;
15 3         7 push @IDS => $code;
16 3         9 return $#IDS;
17             }
18              
19             sub run {
20 3     3 0 8 my $id = shift;
21 3         16 $IDS[$id]->();
22             }
23              
24             sub after_runtime(&) {
25 3     3 0 24633 my ( $code ) = @_;
26 3         14 my $id = get_id( $code );
27              
28 3         26 B::Hooks::Parser::inject(
29             "; my \$__ENDRUN" . $HOOK_ID++ . " = Hook::AfterRuntime->new($id);"
30             );
31             }
32              
33             sub new {
34 3     3 0 238 my $class = shift;
35 3         8 my ($id) = @_;
36 3         15 bless( \$id, $class );
37             }
38              
39             sub DESTROY {
40 3     3   8342 my $self = shift;
41 3         42 run( $$self );
42             }
43              
44             1;
45              
46             =head1 NAME
47              
48             Hook::AfterRuntime - Run code at the end of the compiling scope's runtime.
49              
50             =head1 DESCRIPTION
51              
52             Useful for creating modules that need a behavior to be added when a module that
53             uses them completes its runtime. Like L except it
54             triggers for run-time instead of compile-time.
55              
56             Example where it might be handy:
57              
58             #!/usr/bin/perl
59             use strict;
60             use warnings;
61             use Moose;
62              
63             ...
64              
65             # It would be nice not to need this....
66             __PACKAGE__->make_immutable;
67              
68             =head1 SYNOPSYS
69              
70             MooseX/AutoImmute.pm
71              
72             package MooseX::AutoImmute;
73             use strict;
74             use warnings;
75             use Hook::AfterRuntime;
76              
77             sub import {
78             my $class = shift;
79             my $caller = caller;
80             eval "package $caller; use Moose; 1" || die $@;
81             after_runtime { $caller->make_immutable }
82             }
83              
84             1;
85              
86             t/mytest.t
87              
88             #!/usr/bin/perl
89             use strict;
90             use warnings;
91             use MooseX::AutoImmute;
92              
93             ....
94              
95             #EOF
96             # Package is now immutable autamatically
97              
98             =head1 CAVEATS
99              
100             It is important to understand how Hook::AfterRuntime works n order to know its
101             limitations. When you use a module that calls after_runtime() in its import()
102             method, after_runtime() will inject code directly after your import statement:
103              
104             import MooseX::AutoImmute;
105              
106             becomes:
107              
108             import MooseX::AutoImmute; my $__ENDRUNXXXXXXXX = Hook::AfterRuntime->new($id);
109              
110             This creates a Hook::AfterRuntime object in the corrunt scope. This object's id
111             is used to reference the code provided to after_runtime() in
112             MooseX::AutoImmute()'s import() method. When the object falls out of scope the
113             DESTROY() method kicks in and calls the referenced code. This occurs at the end
114             of the file when 'use' is called at the package level.
115              
116             =head2 EDGE CASES
117              
118             =over 4
119              
120             =item Loading in a scope other than package level:
121              
122             If you use the 'use' directive on a level other than the package level, the
123             behavior will trigger when the end of the scope is reached. If that is a
124             subroutine than it will trigger at the end of EVERY call to that subroutine.
125             B
126             package level scope.>
127              
128             package XXX;
129              
130             sub thing {
131             # Happens at compile time
132             use Object::Using::AfterRuntime;
133              
134             # At run time the hook behavior triggers here!
135             }
136              
137             # hook behavior has not triggered
138              
139             thing()
140              
141             # Hook behavior has triggered
142              
143             1;
144              
145             =item require, and use class ();
146              
147             When require and use class () are used the import method is not called,
148             thus the hook is never installed.
149              
150             =item class->import
151              
152             The hook effects the code that is currently compiling. calling
153             class->import happens after the compilation phase. You must wrap the
154             statement in a BEGIN {} to call import manually. Failure to do this will
155             result in the hook triggering in the wrong class, or not at all.
156              
157             =back
158              
159             =head1 USER WARNING
160              
161             When you write a class that depends on this hook you should insert the
162             following warning into the docs:
163              
164             This class uses L, it B be imported at the package
165             level at compile time. This means 'use MODULE' or 'BEGIN { require MODULE;
166             MODULE->import() }'. Failure to use one of these correct forms will result in a
167             missing hook and unpredictable behavior.
168              
169             =head1 SEE ALSO
170              
171             =over 4
172              
173             =item B::Hooks::EndOfScope
174              
175             Does almost the same thing, except it is triggered after compile-time instead
176             of run-time.
177              
178             =back
179              
180             =head1 FENNEC PROJECT
181              
182             This module is part of the Fennec project. See L for more details.
183             Fennec is a project to develop an extendable and powerful testing framework.
184             Together the tools that make up the Fennec framework provide a potent testing
185             environment.
186              
187             The tools provided by Fennec are also useful on their own. Sometimes a tool
188             created for Fennec is useful outside the greator framework. Such tools are
189             turned into their own projects. This is one such project.
190              
191             =over 2
192              
193             =item L - The core framework
194              
195             The primary Fennec project that ties them all together.
196              
197             =back
198              
199             =head1 AUTHORS
200              
201             Chad Granum L
202              
203             =head1 COPYRIGHT
204              
205             Copyright (C) 2010 Chad Granum
206              
207             Hook-AfterRuntime is free software; Standard perl licence.
208              
209             Hook-AfterRuntime is distributed in the hope that it will be useful, but WITHOUT
210             ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
211             FOR A PARTICULAR PURPOSE. See the license for more details.