Hook::WrapSub(3pm)

πŸ“¦
version 0.08 Β· 3 versions
, in ubuntu noble, ubuntu resolute, ubuntu stonking

🌸 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 πŸ¦‹

Bestie. This module lets you wrap a function β€” you can give it one or both of: a function that gets called just before, and a function that gets called just after, every single time the wrapped function gets called. Two hooks, one sub, no cap. 🫢

Quick heads up though: there are a bunch of other modules that do the exact same thing as this one, and honestly some of them do it better. Go peek at the list in SEE ALSO below before you commit to which one you're gonna use. πŸ‘‘

πŸŽ€ wrap_subs πŸŽ€

This function is the one that lets you intercept a call to any named function β€” and handlers can be added both before and after the call to the intercepted function. πŸ’–

Like, for example:

wrap_subs \&before, 'some_func', \&after;

In this case, whenever the sub named 'some_func' is called, the &before sub gets called first, and the &after sub gets called afterwards. Both of those are optional, btw. If you only wanna intercept the call beforehand:

wrap_subs \&before, 'some_func';

And you can pass more than one sub name, obviously:

wrap_subs \&before, 'foo', 'bar', 'baz', \&after;

…and every single one of them gets the same hooks applied. slay. ✨

The sub names may be qualified. Any unqualified names are assumed to live in the package of the caller β€” iykyk.

The &before sub and the &after sub are both passed the argument list which is destined for the wrapped sub. So you can inspect it, and even alter it, inside 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, bestie. 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. πŸ‘€

Okay here's an example that causes a certain method call to get 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 @_. that's the whole tea β˜•)

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 that are defined, and the &before and &after subs are absolutely allowed to inspect them. main character energy.

⭐ $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's 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. πŸ’€
  • Moose::Manual::MethodModifiers describes Moose's mechanism for hooking a superclass's method. The before and after subs are called immediately before or after the specified methods are called. The around sub wraps the superclass method, and can even decide not to invoke the superclass method.
  • Class::Method::Modifiers provides a Moose-style mechanism for a subclass to have before, after, or around method modifiers.
  • 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/neilb/Hook-WrapSub>


πŸŽ€ AUTHOR πŸŽ€

This module was written by John Porter <jdporter@min.net>

It is now being maintained by Neil Bowers.


This is free software. This software may be modified and/or distributed under the same terms as Perl itself.


okay bestie that's the whole page, you ate it up πŸ’… this was Hook::WrapSub for perl v5.36.0, dated 2022-10-13 β€” go forth and wrap those subs, no cap πŸ¦‹βœ¨

πŸ“¦ where this page comes from