NAME
Sub::Override - Perl extension for easily overriding subroutines
SYNOPSIS
use Sub::Override;
sub foo { 'original sub' };
print foo(); # prints 'original sub'
my $override = Sub::Override->new( foo => sub { 'overridden sub' } );
print foo(); # prints 'overridden sub'
$override->restore;
print foo(); # prints 'original sub'
DESCRIPTION
The Problem
Sometimes subroutines need to be overridden. In fact, your author does this constantly for tests. Particularly when testing, using a Mock Object can be overkill when all you want to do is override one tiny, little function.
Overriding a subroutine is often done with syntax similar to the following.
{
local *Some::sub = sub {'some behavior'};
# do something
}
# original subroutine behavior restored
This has a few problems.
{
local *Get::some_feild = { 'some behavior' };
# do something
}
In the above example, not only have we probably mispelled the subroutine name, but even if their had been a subroutine with that name, we haven't overridden it. These two bugs can be subtle to detect.
Further, if we're attempting to localize the effect by placing this code in a block, the entire construct is cumbersome.
Hook::LexWrap also allows us to override sub behavior, but I can never remember the exact syntax.
An easier way to replace subroutines
Instead, Sub::Override
allows the programmer to simply name the sub to replace and to supply a sub to replace it with.
my $override = Sub::Override->new('Some::sub', sub {'new data'});
# which is equivalent to:
my $override = Sub::Override->new;
$override->replace('Some::sub', sub { 'new data' });
You can replace multiple subroutines, if needed:
$override->replace('Some::sub1', sub { 'new data1' })
->replace('Some::sub2', sub { 'new data2' })
->replace('Some::sub3', sub { 'new data3' });
(Chaining calls is not required)
Restoring subroutines
If the object falls out of scope, the original subs are restored. However, if you need to restore a subroutine early, just use the restore method:
my $override = Sub::Override->new('Some::sub', sub {'new data'});
# do stuff
$override->restore;
Which is somewhat equivalent to:
{
my $override = Sub::Override->new('Some::sub', sub {'new data'});
# do stuff
}
If you have override more than one subroutine with an override object, you will have to explicitly name the subroutine you wish to restore:
$override->restore('This::sub');
Failure to fully qualify the subroutine name will assume the current package.
package Foo;
use Sub::Override;
sub foo { 23 };
my $override = Sub::Override->new( foo => sub { 42 } ); # assumes Foo::foo
print foo(); # prints 42
$override->restore;
print foo(); # prints 23
EXPORT
None by default.
BUGS
Probably. Tell me about 'em.
SEE ALSO
Hook::LexWrap -- can also override subs, but with different capabilities
Test::MockObject -- use this if you need to alter an entire class
AUTHOR
Curtis "Ovid" Poe, <eop_divo_sitruc@yahoo.com>
Reverse the name to email me.
COPYRIGHT AND LICENSE
Copyright (C) 2004 by Curtis "Ovid" Poe
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.2 or, at your option, any later version of Perl 5 you may have available.