1Hook::LexWrap(3) User Contributed Perl Documentation Hook::LexWrap(3)
2
3
4
6 Hook::LexWrap - Lexically scoped subroutine wrappers
7
9 version 0.26
10
12 use Hook::LexWrap;
13
14 sub doit { print "[doit:", caller, "]"; return {my=>"data"} }
15
16 SCOPED: {
17 wrap doit =>
18 pre => sub { print "[pre1: @_]\n" },
19 post => sub { print "[post1:@_]\n"; $_[1]=9; };
20
21 my $temporarily = wrap doit =>
22 post => sub { print "[post2:@_]\n" },
23 pre => sub { print "[pre2: @_]\n "};
24
25 @args = (1,2,3);
26 doit(@args); # pre2->pre1->doit->post1->post2
27 }
28
29 @args = (4,5,6);
30 doit(@args); # pre1->doit->post1
31
33 Hook::LexWrap allows you to install a pre- or post-wrapper (or both)
34 around an existing subroutine. Unlike other modules that provide this
35 capacity (e.g. Hook::PreAndPost and Hook::WrapSub), Hook::LexWrap
36 implements wrappers in such a way that the standard "caller" function
37 works correctly within the wrapped subroutine.
38
39 To install a prewrappers, you write:
40
41 use Hook::LexWrap;
42
43 wrap 'subroutine_name', pre => \&some_other_sub;
44
45 #or: wrap *subroutine_name, pre => \&some_other_sub;
46
47 The first argument to "wrap" is a string containing the name of the
48 subroutine to be wrapped (or the typeglob containing it, or a reference
49 to it). The subroutine name may be qualified, and the subroutine must
50 already be defined. The second argument indicates the type of wrapper
51 being applied and must be either 'pre' or 'post'. The third argument
52 must be a reference to a subroutine that implements the wrapper.
53
54 To install a post-wrapper, you write:
55
56 wrap 'subroutine_name', post => \&yet_another_sub;
57
58 #or: wrap *subroutine_name, post => \&yet_another_sub;
59
60 To install both at once:
61
62 wrap 'subroutine_name',
63 pre => \&some_other_sub,
64 post => \&yet_another_sub;
65
66 or:
67
68 wrap *subroutine_name,
69 post => \&yet_another_sub, # order in which wrappers are
70 pre => \&some_other_sub; # specified doesn't matter
71
72 Once they are installed, the pre- and post-wrappers will be called
73 before and after the subroutine itself, and will be passed the same
74 argument list.
75
76 The pre- and post-wrappers and the original subroutine also all see the
77 same (correct!) values from "caller" and "wantarray".
78
79 Short-circuiting and long-circuiting return values
80 The pre- and post-wrappers both receive an extra argument in their @_
81 arrays. That extra argument is appended to the original argument list
82 (i.e. is can always be accessed as $_[-1]) and acts as a place-holder
83 for the original subroutine's return value.
84
85 In a pre-wrapper, $_[-1] is -- for obvious reasons -- "undef". However,
86 $_[-1] may be assigned to in a pre-wrapper, in which case Hook::LexWrap
87 assumes that the original subroutine has been "pre-empted", and that
88 neither it, nor the corresponding post-wrapper, nor any wrappers that
89 were applied before the pre-empting pre-wrapper was installed, need be
90 run. Note that any post-wrappers that were installed after the pre-
91 empting pre-wrapper was installed will still be called before the
92 original subroutine call returns.
93
94 In a post-wrapper, $_[-1] contains the return value produced by the
95 wrapped subroutine. In a scalar return context, this value is the
96 scalar return value. In an list return context, this value is a
97 reference to the array of return values. $_[-1] may be assigned to in a
98 post-wrapper, and this changes the return value accordingly.
99
100 Access to the arguments and return value is useful for implementing
101 techniques such as memoization:
102
103 my %cache;
104 wrap fibonacci =>
105 pre => sub { $_[-1] = $cache{$_[0]} if $cache{$_[0]} },
106 post => sub { $cache{$_[0]} = $_[-1] };
107
108 or for converting arguments and return values in a consistent manner:
109
110 # set_temp expects and returns degrees Fahrenheit,
111 # but we want to use Celsius
112 wrap set_temp =>
113 pre => sub { splice @_, 0, 1, $_[0] * 1.8 + 32 },
114 post => sub { $_[-1] = ($_[0] - 32) / 1.8 };
115
116 Lexically scoped wrappers
117 Normally, any wrappers installed by "wrap" remain attached to the
118 subroutine until it is undefined. However, it is possible to make
119 specific wrappers lexically bound, so that they operate only until the
120 end of the scope in which they're created (or until some other specific
121 point in the code).
122
123 If "wrap" is called in a non-void context:
124
125 my $lexical = wrap 'sub_name', pre => \&wrapper;
126
127 it returns a special object corresponding to the particular wrapper
128 being placed around the original subroutine. When that object is
129 destroyed -- when its container variable goes out of scope, or when its
130 reference count otherwise falls to zero (e.g. "undef $lexical"), or
131 when it is explicitly destroyed ("$lexical->DESTROY") -- the
132 corresponding wrapper is removed from around the original subroutine.
133 Note, however, that all other wrappers around the subroutine are
134 preserved.
135
136 Anonymous wrappers
137 If the subroutine to be wrapped is passed as a reference (rather than
138 by name or by typeglob), "wrap" does not install the wrappers around
139 the original subroutine. Instead it generates a new subroutine which
140 acts as if it were the original with those wrappers around it. It then
141 returns a reference to that new subroutine. Only calls to the original
142 through that wrapped reference invoke the wrappers. Direct by-name
143 calls to the original, or calls through another reference, do not.
144
145 If the original is subsequently wrapped by name, the anonymously
146 wrapped subroutine reference does not see those wrappers. In other
147 words, wrappers installed via a subroutine reference are completely
148 independent of those installed via the subroutine's name (or typeglob).
149
150 For example:
151
152 sub original { print "ray" }
153
154 # Wrap anonymously...
155 my $anon_wrapped = wrap \&original, pre => sub { print "do..." };
156
157 # Show effects...
158 original(); # prints "ray"
159 $anon_wrapped->(); # prints "do..ray"
160
161 # Wrap nonymously...
162 wrap *original,
163 pre => sub { print "fa.." },
164 post => sub { print "..mi" };
165
166 # Show effects...
167 original(); # now prints "fa..ray..mi"
168 $anon_wrapped->(); # still prints "do...ray"
169
171 "Can't wrap non-existent subroutine %s"
172 An attempt was made to wrap a subroutine that was not defined at
173 the point of wrapping.
174
175 "'pre' value is not a subroutine reference"
176 The value passed to "wrap" after the 'pre' flag was not a
177 subroutine reference. Typically, someone forgot the "sub" on the
178 anonymous subroutine:
179
180 wrap 'subname', pre => { your_code_here() };
181
182 and Perl interpreted the last argument as a hash constructor.
183
184 "'post' value is not a subroutine reference"
185 The value passed to "wrap" after the 'post' flag was not a
186 subroutine reference.
187
188 "Uselessly wrapped subroutine reference in void context" (warning only)
189 When the subroutine to be wrapped is passed as a subroutine
190 reference, "wrap" does not install the wrapper around the original,
191 but instead returns a reference to a subroutine which wraps the
192 original (see "Anonymous wrappers").
193
194 However, there's no point in doing this if you don't catch the
195 resulting subroutine reference.
196
198 Schwern made me do this (by implying it wasn't possible ;-)
199
201 Sub::Prepend
202
204 There are undoubtedly serious bugs lurking somewhere in code this funky
205 :-)
206
207 Bug reports and other feedback are most welcome.
208
209 Bugs may be submitted through the RT bug tracker
210 <https://rt.cpan.org/Public/Dist/Display.html?Name=Hook-LexWrap> (or
211 bug-Hook-LexWrap@rt.cpan.org <mailto:bug-Hook-LexWrap@rt.cpan.org>).
212
214 Damian Conway <damian@conway.org>
215
217 • Karen Etheridge <ether@cpan.org>
218
219 • Alexandr Ciornii <alexchorny@gmail.com>
220
221 • Father Chrysostomos <sprout@cpan.org>
222
224 This software is copyright (c) 2001 by Damian Conway.
225
226 This is free software; you can redistribute it and/or modify it under
227 the same terms as the Perl 5 programming language system itself.
228
229
230
231perl v5.34.0 2021-07-22 Hook::LexWrap(3)