NAME

Sub::Mage - Override, Restore and manipulate subroutines on-the-fly, without magic.

DESCRIPTION

On the very rare occasion you may need to override a subroutine for any particular reason. This module will help you do that with minimal fuss. Afterwards, when you're done, you can simply restore the subroutine back to its original state. Used on its own will override/restore a sub from the current script, but called from a class it will alter that classes subroutine. As long as the current package has access to it, it may be altered. Sub::Mage now has the ability to manipulate subroutines by creating after and before modifier hooks, or create new subroutines on the go with conjur. New debugging functionality has been added also. With sub_alert you can see when any subroutines (not Sub::Mage imported ones) are being called.

SYNOPSIS

# Single file

use Sub::Mage;

sub greet { print "Hello, World!"; }

greet; # prints Hello, World!

override 'greet' => sub {
    print "Goodbye, World!";
};

greet; # now prints Goodbye, World!

restore 'greet'; # restores it back to its original state

Changing a class method, by example

# Foo.pm

use Sub::Mage;

sub new { my $self = {}; return bless $self, __PACKAGE__; }

sub hello {
    my $self = shift;

    $self->{name} = "World";
}

# test.pl

use Foo;

my $foo = Foo->new;

Foo->override( 'hello' => sub {
    my $self = shift;

    $self->{name} = "Town";
});

print "Hello, " . $foo->hello . "!\n"; # prints Hello, Town!

Foo->restore('hello');

print "Hello, " . $foo->hello . "!\n"; # prints Hello, World!

INCANTATIONS

When you use Sub::Mage there are currently a couple of options you can pass to it. One is :5.010. This will import the 5.010 feature.. this has nothing to do with subs, but I like this module, so it's there. The other is :Debug. If for some reason you want some kind of debugging going on when you override, restore, conjur or create hook modifiers then this will enable it for you. It can get verbose, so use it only when you need to.

use Sub::Mage ':5.010';

say "It works!";

#--

use Sub::Mage qw/:5.010 :Debug/;

conjur 'asub' => sub { }; # notifies you with [debug] that a subroutine was conjured

Now with importing we can turn a perfectly normal package into a class, sort of. It saves you from creating sub new { ... }

# MyApp.pm
package MyApp;

use Sub::Mage qw/:5.010 :Class/;

1;

# test.pl
my $foo = MyApp->new;

MyApp->conjur( name => sub {
    my ($self, $name) = @_;

    $self->{name} = $name;
    say "Set name to $name";
});

MyApp->conjur( getName => sub { return shift->{name}; });

$foo->name('World');

say $foo->getName;

Above we created a basically blank package, passed :Class to the Sub::Mage import method, then controlled the entire class from test.pl.

SPELLS

override

Overrides a subroutine with the one specified. On its own will override the one in the current script, but if you call it from a class, and that class is visible, then it will alter the subroutine in that class instead. Overriding a subroutine inherits everything the old one had, including $self in class methods.

override 'subname' => sub {
    # do stuff here
};

# class method
FooClass->override( 'subname' => sub {
    my $self = shift;

    # do stuff
});

restore

Restores a subroutine to its original state.

override 'foo' => sub { };

restore 'foo'; # and we're back in the room

after

Adds an after hook modifier to the subroutine. Anything in the after subroutine is called directly after the original sub. Hook modifiers can also be restored.

sub greet { print "Hello, "; }

after 'greet' => sub { print "World!"; };

greet(); # prints Hello, World!

before

Very similar to after, but calls the before subroutine, yes that's right, before the original one.

sub bye { print "Bye!"; }

before 'bye' => sub { print "Good "; };

bye(); # prints Good Bye!

conjur

"Conjurs" a subroutine into the current script or a class. By conjur I just mean create. It will not allow you to override a subroutine using conjur.

conjur 'test' => sub { print "In test\n"; }
test;

Foo->conjur( hello => sub {
    my ($self, $name) = @_;

    print "Hello, $name!\n";
});

sub_alert

Very verbose: Adds a before hook modifier to every subroutine in the package to let you know when a sub is being called. Great for debugging if you're not sure a method is being ran.

__PACKAGE__->sub_alert;

# define a normal sub
sub test { return "World"; }

say "Hello, " . test(); # prints Hello, World but also lets you know 'test' in 'package' was called.

duplicate

Duplicates a subroutine from one class to another. Probably rarely used, but the feature is there if you need it.

use ThisPackage;
use ThatPackage;

duplicate 'subname' => ( from => 'ThisPackage', to => 'ThatPackage' );

ThatPackage->subname; # duplicate of ThisPackage->subname

AUTHOR

Brad Haywood <brad@geeksware.net>

LICENSE

You may distribute this code under the same terms as Perl itself.