NAME¶
Hook::WrapSub - wrap subs with pre- and post-call hooks
SYNOPSIS¶
use Hook::WrapSub qw( wrap_subs unwrap_subs );
wrap_subs \&before, 'some_func', 'another_func', \&after;
unwrap_subs 'some_func';
DESCRIPTION¶
There are a number of other modules that provide the same functionality as this
module, some of them better. Have a look at the list in SEE ALSO, below,
before you decide which to use.
wrap_subs¶
This function enables intercepting a call to any named function; handlers may be
added both before and after the call to the intercepted function.
For example:
wrap_subs \&before, 'some_func', \&after;
In this case, whenever the sub named 'some_func' is called, the &before sub
is called first, and the &after sub is called afterwards. These are both
optional. If you only want to intercept the call beforehand:
wrap_subs \&before, 'some_func';
You may pass more than one sub name:
wrap_subs \&before, 'foo', 'bar', 'baz', \&after;
and each one will have the same hooks applied.
The sub names may be qualified. Any unqualified names are assumed to reside in
the package of the caller.
The &before sub and the &after sub are both passed the argument list
which is destined for the wrapped sub. This can be inspected, and even
altered, in the &before sub:
sub before {
ref($_[1]) && $_[1] =~ /\bARRAY\b/
or croak "2nd arg must be an array-ref!";
@_ or @_ = qw( default values );
# if no args passed, insert some default values
}
The &after sub is also passed this list. Modifications to it will
(obviously) not be seen by the wrapped sub, but the caller will see the
changes, if it happens to be looking.
Here's an example that causes a certain method call to be redirected to a
specific object. (Note, we use splice to change $_[0], because assigning
directly to $_[0] would cause the change to be visible to the caller, due to
the magical aliasing nature of @_.)
my $handler_object = new MyClass;
Hook::WrapSub::wrap_subs
sub { splice @_, 0, 1, $handler_object },
'MyClass::some_method';
my $other_object = new MyClass;
$other_object->some_method;
# even though the method is invoked on
# $other_object, it will actually be executed
# with a 0'th argument = $handler_obj,
# as arranged by the pre-call hook sub.
Package Variables¶
There are some Hook::WrapSub package variables defined, which the &before
and &after subs may inspect.
- $Hook::WrapSub::name
- This is the fully qualified name of the wrapped sub.
- @Hook::WrapSub::caller
- This is a list which strongly resembles the result of a call to the
built-in function "caller"; it is provided because calling
"caller" will in fact produce confusing results; if your sub is
inclined to call "caller", have it look at this variable
instead.
- @Hook::WrapSub::result
- This contains the result of the call to the wrapped sub. It is empty in
the &before sub. In the &after sub, it will be empty if the sub
was called in a void context, it will contain one value if the sub was
called in a scalar context; otherwise, it may have any number of elements.
Note that the &after function is not prevented from modifying the
contents of this array; any such modifications will be seen by the
caller!
This simple example shows how Hook::WrapSub can be used to log certain
subroutine calls:
sub before {
print STDERR <<" EOF";
About to call $Hook::WrapSub::name( @_ );
Wantarray=$Hook::WrapSub::caller[5]
EOF
}
sub after {
print STDERR <<" EOF";
Called $Hook::WrapSub::name( @_ );
Result=( @Hook::WrapSub::result )
EOF
@Hook::WrapSub::result
or @Hook::WrapSub::result = qw( default return );
# if the sub failed to return something...
}
Much more elaborate uses are possible. Here's one one way it could be used with
database operations:
my $dbh; # initialized elsewhere.
wrap_subs
sub {
$dbh->checkpoint
},
'MyDb::update',
'MyDb::delete',
sub {
# examine result of sub call:
if ( $Hook::WrapSub::result[0] ) {
# success
$dbh->commit;
}
else {
# failure
$dbh->rollback;
}
};
unwrap_subs¶
This removes the most recent wrapping of the named subs.
NOTE: Any given sub may be wrapped an unlimited number of times. A
"stack" of the wrappings is maintained internally. wrap_subs
"pushes" a wrapping, and unwrap_subs "pops".
SEE ALSO¶
Hook::LexWrap provides a similar capability to "Hook::WrapSub", but
has the benefit that the "caller()" function works correctly within
the wrapped subroutine.
Sub::Prepend lets you provide a sub that will be called before a named sub. The
"caller()" function works correctly in the wrapped sub.
Sub::Mage provides a number of related functions. You can provide pre- and
post-call hooks, you can temporarily override a function and then restore it
later, and more.
Class::Hook lets you add pre- and post-call hooks around any methods called by
your code. It doesn't support functions.
Hook::Scope lets you register callbacks that will be invoked when execution
leaves the scope they were registered in.
Hook::PrePostCall provides an OO interface for wrapping a function with pre- and
post-call hook functions. Last updated in 1997, and marked as alpha.
Hook::Heckle provides an OO interface for wrapping pre- and post-call hooks
around functions or methods in a package. Not updated sinc 2003, and has a 20%
failed rate on CPAN Testers.
Class::Wrap provides the "wrap()" function, which takes a coderef and
a package name. The coderef is invoked every time a method in the package is
called.
Sub::Versive lets you stack pre- and post-call hooks. Last updated in 2001.
REPOSITORY¶
<
https://github.com/neilbowers/Hook-WrapSub>
AUTHOR¶
jdporter@min.net (John Porter)
COPYRIGHT¶
This is free software. This software may be modified and/or distributed under
the same terms as Perl itself.