File Coverage

blib/lib/Hook/AfterRuntime.pm
Criterion Covered Total %
statement 27 27 100.0
branch n/a
condition n/a
subroutine 10 10 100.0
pod 0 4 0.0
total 37 41 90.2


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