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.