NAME

   Wrap::Sub - Object Oriented subroutine wrapper with pre and post hooks,
   and more.

SYNOPSIS

       use Wrap::Sub;

   Basic functionality example

       my $wrapper = Wrap::Sub->new;

       # create the wrapped sub object

       my $foo_obj  = $wrapper->wrap(
           'My::Module::foo',
           pre  => sub { print "$Wrap::Sub::name in pre\n"; },
           post => sub { print "$Wrap::Sub::name in post\n"; },
       );

       # add/change/remove a routine via a method call (send in undef to remove)

       $foo_obj->pre(sub { print "changed pre\n"; } );
       $foo_obj->post(sub { print "changed post\n"; } );

       # name of sub

       $foo_obj->name;

       # unwrap and rewrap

       $foo_obj->unwrap;
       $foo_obj->rewrap;

       # wrapped or not?

       my $is_wrapped = $foo_obj->is_wrapped;

       # list all subs wrapped under the current wrap object

       my @wrapped_subs = $wrapper->wrapped_subs;

       # retrieve all wrapped sub objects

       my @sub_objects = $wrapper->wrapped_objects;

   Here's an example that shows how you can get elapsed time of a sub
   (this example requires Time::HiRes)

       my $pre_cref = sub {
           return gettimeofday();
       };

       my $post_cref = sub {
           my $pre_return = shift;
           my $time = gettimeofday() - $pre_return->[0];
           print "$Wrap::Sub::name finished in $time seconds\n";
       };

       $foo_obj->pre($pre_cref);
       $foo_obj->post($post_cref);

   Manipulate the return from the original subroutine, take action, then
   return the modified results

       my $post_cref = sub {
           my ($pre_return, $sub_return) = @_;

           if ($sub_return->[0] != 1){
               die "$Wrap::Sub::name returned an error\n";
           }
           else {
               $sub_return->[0] = 100;
               return $sub_return->[0];
           }
       };

       $foo_obj->post($post_cref, post_return => 1);

   Get an ordered list (array of array references) of the last expression
   evaluated in all sub object pre() and post() functions

       my @pre_results = $wrapper->pre_results;
       my @post_results = $wrapper->post_results;

       for my $sub_post_result (@post_results){
           print "$sub_post_result->[0]\n";
       }

   Wrap all subs in a module (does not include imported subs), and have
   them all perform the same actions

       my $wrapper = Wrap::Sub->new(
           pre  => sub { print "start $Wrap::Sub::name\n"; },
           post => sub { print "finish $Wrap::Sub::name\n"; },
       );

       # wrapping a module returns an href with the sub name as the key,
       # and the value being the wrapped sub object

       my $module_subs = $wrapper->wrap('My::Module');

       # unwrap them all, and confirm

       for my $sub_name (keys %$module_subs){
           my $sub_obj = $module_subs->{$sub_name};

           print "$sub_name is wrapped\n" if $sub_obj->is_wrapped;

           $sub_obj->unwrap;

           if ($sub_obj->is_wrapped) {
               die "$sub_name not unwrapped!"
           }
       }

DESCRIPTION

   This module allows you to wrap subroutines with pre and post hooks
   while keeping track of your wrapped subs. It also allows you to easily
   wrap all subs within a module (while filtering out the subs that are
   imported).

   Thanks to code taken out of Hook::LexWrap, caller() works properly
   within the wrapped subs.

   There are other modules that do this, see "SEE ALSO". I wrote it out of
   sheer curiosity and experience, not because I didn't check the CPAN for
   existing modules that do the same thing.

WRAP OBJECT METHODS

new(%opts)

   Instantiates and returns a new Wrap::Sub object, ready to be used to
   start creating wrapped sub objects.

   Options (note that if these are set in new(), all subs wrapped with
   this object will exhibit the same behaviour. Set in wrap() or use pre()
   and post() methods to individualize wrapped subroutine behaviour).

   pre => $cref

     A code reference containing actions that will be executed prior to
     executing the sub that's wrapped. Receives the parameters that are
     sent into the wrapped sub (@_). Has access to $Wrap::Sub::name
     parameter, which holds the name of the original wrapped sub.

   post => $cref

     A code reference containing actions that will be executed after the
     wrapped sub is executed. Has access to $Wrap::Sub::name parameter,
     which holds the name of the original wrapped sub.

     Receives an array reference with two elements, each another array
     reference. The first inner reference contains the return value(s)
     from the pre hook, and the second contains the return value(s) from
     the wrapped sub. If neither pre or the actual sub have return values,
     the respective inner array reference will be empty.

     Returns whatever you decide you want it to. See post_return parameter
     for further details on returning values.

   post_return => Bool

     Set this to true if you want your post() hook to return its results,
     and false if you want the return value(s) from the actual wrapped sub
     instead. Disabled by default (ie. you'll get the return from the
     original sub).

wrap('sub', %opts)

   Instantiates and returns a new wrapped sub object on each call. sub is
   the name of the subroutine to wrap (requires full package name if the
   sub isn't in main::).

   Options:

   See new() for a description of the parameters. Setting them here allows
   you to individualize behaviour of the hooks for each wrapped
   subroutine.

wrapped_subs

   Returns a list of all the names of the subs that are currently wrapped
   under the parent wrap object.

wrapped_objects

   Returns a list of all sub objects underneath the parent wrap object,
   regardless if its sub is currently wrapped or not.

is_wrapped('Sub::Name')

   Returns 1 if the sub currently under the parent wrap object is wrapped
   or not, and 0 if not. Croaks if there hasn't been a child sub object
   created with this sub name.

pre_results

   As each wrapped sub is called where a pre() method is set, we'll stash
   the last expression evaluated in it, and push the results to an array.
   This method will fetch that array.

   Each entry is an array reference per pre() call, containing the
   returned data.

post_results

   As each wrapped sub is called where a post() method is set, we'll stash
   the last expression evaluated in it, and push the results to an array.
   This method will fetch that array.

   Each entry is an array reference per post() call, containing the
   returned data.

WRAPPED SUB OBJECT METHODS

   These methods are for the children wrapped sub objects returned from
   the parent wrap object. See "WRAP OBJECT METHODS" for methods related
   to the parent wrap object.

name

   Returns the name of the sub represented by this sub object.

pre($cref)

   Send in a code reference containing actions that you want to have
   performed prior to the wrapped sub being executed. Has access to
   $Wrap::Sub::name parameter, which holds the name of the original
   wrapped sub.

post($cref, post_return => Bool)

   A code reference containing actions that will be executed after the
   wrapped sub is executed. Has access to $Wrap::Sub::name parameter,
   which holds the name of the original wrapped sub.

   The code supplied receives an array reference containing an array
   reference holding the return values from pre() and a second array
   reference containing the return values from the actual wrapped sub. If
   neither pre or the actual sub have return values, the respective array
   reference will be empty.

   The optional parameter post_return specifies that you want the return
   value(s) from this function instead of the return value(s) generated by
   the wrapped sub. Disabled by default.

unwrap

   Restores the original functionality back to the sub, and runs reset()
   on the object.

rewrap

   Re-wraps the sub within the object after calling unwrap on it.

reset

   Resets the functional parameters (pre, post and post_return), along
   with called() and called_with back to undef/false. Does not restore the
   sub back to its original state.

is_wrapped

   Returns true (1) if the sub the object refers to is currently wrapped,
   and false (0) if not.

called

   Returns true (1) if the sub being wrapped has been called, and false
   (0) if not.

called_with

   Returns an array of the parameters sent to the subroutine. croak()s if
   we're called before the wrapped sub has been called.

NOTES

   This module has a backwards parent-child relationship. To use, you
   create a wrap object using "WRAP OBJECT METHODS" new and wrap methods,
   thereafter, you use the returned wrapped sub object "WRAPPED SUB OBJECT
   METHODS" to perform the work.

SEE ALSO

   This module was created for my own sheer curiosity and experience.
   There are quite a few like it. I've never used any of them (this list
   was taken from Hook::WrapSub):

   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.

AUTHOR

   Steve Bertrand, <steveb at cpan.org>

BUGS

   Please report any bugs or requests at
   https://github.com/stevieb9/wrap-sub/issues

REPOSITORY

   https://github.com/stevieb9/wrap-sub

BUILD RESULTS

   CPAN Testers: http://matrix.cpantesters.org/?dist=Wrap-Sub

SUPPORT

   You can find documentation for this module with the perldoc command.

       perldoc Wrap::Sub

LICENSE AND COPYRIGHT

   Copyright 2016 Steve Bertrand.

   This program is free software; you can redistribute it and/or modify it
   under the terms of either: the GNU General Public License as published
   by the Free Software Foundation; or the Artistic License.

   See http://dev.perl.org/licenses/ for more information.