Module::Replace - Replace functionality in other modules


Module-Replace documentation Contained in the Module-Replace distribution.

Index


Code Index:

NAME

Top

Module::Replace - Replace functionality in other modules

VERSION

Top

Version 0.01

SYNOPSIS

Top

    use Module::Replace 'Other::Module' => qw(new);

DESCRIPTION

Top

The purpose of this module is to allow you to override functions in one module with the same-named functions in another.

This can be a global change, or a temporary change.

The reasons why you may want to do this include:

USAGE

Top

There are two types of usage: global and local replacement.

Global replacement

This is primarily targetted at frameworks. Here you call:

    use Module::Replace 'YourFramework::Type', qw(new);

from within the derived object. This will both call use base 'YourFramework::Type' and override new with your own. Note that access to the original new method is still available via SUPER_new, e.g.:

    sub new {
        my $class = shift;
        # allow re-derivations
        $class = __PACKAGE__ if $class eq 'YourFramework::Type';
        my $self = bless $class->SUPER_new(), $class;
        # ...
    }

Local replacement

Sometimes you only want to replace a function for a little while. For example, changing the way that File::Spec::catdir works only when calling another function. Here you call the replace and restore functions directly.

    use Module::Replace;
    Module::Replace::replace('File::Spec', \'File::Spec::UNIX', qw(catdir));
    Some::Other::function();
    Module::Replace::restore('File::Spec', \'File::Spec::UNIX');

Note that if you leave off the reference to the source package, it will assume the caller package.

This will cause catdir to work UNIX-like on all platforms for the duration of Some::Other::function().

It is up to you to ensure that exceptions are handled so that the methods are restored at the proper time.

FUNCTIONS

Top

replace

Input:

1

Package to replace.

2

Reference to package that contains the wanted function (optional - defaults to caller's package)

3

List of functions to replace. Each function will be renamed to SUPER_$func so that the overridden function will work

restore

Input:

1

Package that is overridden

2

Reference to package that contains the wanted function (optional - defaults to caller's package)

AUTHOR

Top

Darin McBride, <dmcbride at cpan.org>

BUGS

Top

Please report any bugs or feature requests to bug-module-replace at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Module-Replace. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

Top

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

    perldoc Module::Replace




You can also look for information at:

* RT: CPAN's request tracker

http://rt.cpan.org/NoAuth/Bugs.html?Dist=Module-Replace

* AnnoCPAN: Annotated CPAN documentation

http://annocpan.org/dist/Module-Replace

* CPAN Ratings

http://cpanratings.perl.org/d/Module-Replace

* Search CPAN

http://search.cpan.org/dist/Module-Replace

ACKNOWLEDGEMENTS

Top

COPYRIGHT & LICENSE

Top


Module-Replace documentation Contained in the Module-Replace distribution.
package Module::Replace;

use warnings;
use strict;

#use 5.010;

our $VERSION = '0.02';


sub import
{
    my $self  = shift;
    my $class = shift;
    my ($caller) = caller(0);

    return 1 unless $class;

    # first, load the module, and make the caller derived from it.
    # 'base' does a lot of work - let's abuse that.
    eval qq[
                package $caller;
                use base '$class';
                ];
    die $@ if $@;
    replace($class, \$caller, @_) if @_;
    1;
}

my %overrides;
sub replace
{
    my $class = shift;
    my ($caller) = ref $_[0] && ref $_[0] eq 'SCALAR' ? ${shift()} : caller(0);

    # now, replace desired methods.
    for my $func (@_)
    {
        no strict 'refs';
        no warnings;
        local ($^W) = 0; # in case "-w" is used
        *{"${class}::SUPER_$func"} = \&{"${class}::$func"} if ${"${class}::"}{$func};
        *{"${class}::$func"} = \&{"${caller}::$func"};
        # keep track of what was overridden for reversals.
        $overrides{$caller}{$class}{$func}++;
    }
}

sub restore
{
    my $class = shift;
    my ($caller) = ref $_[0] && ref $_[0] eq 'SCALAR' ? ${shift()} : caller(0);

    for my $func (keys %{$overrides{$caller}{$class}})
    {
        no strict 'refs';
        no warnings;
        local ($^W) = 0; # in case "-w" is used
        if (exists ${"${class}::"}{"SUPER_$func"})
        {
            *{"${class}::$func"} = \&{"${class}::SUPER_$func"};
            delete ${"${class}::"}{"SUPER_$func"};
        }
        else
        {
            delete ${"${class}::"}{$func};
        }
    }
}

1; # End of Module::Replace