use warnings;
use strict;
use lib '.';
#use Count;
print One::foo();
{
#my $count = Count->new;
my $bar = Count->mock;
print One::foo();
}
print One::foo();
BEGIN{
package One;
sub foo {
return "foo\n";
}
1;
package Count;
sub new {
return bless {}, shift;
}
sub unmock {
my $self = shift;
*One::foo = \&{ $self->{sub} };
}
sub mock {
my $thing = shift;
my $self;
if (ref($thing) eq __PACKAGE__){
$self = $thing;
}
else {
$self = bless {}, __PACKAGE__;
}
use Scalar::Util 'weaken';
weaken $self;
$self->{sub} = \&One::foo;
{
no warnings 'redefine';
*One::foo = sub { $self->{x} = 'x'; return "baz\n"; };
}
return $self;
}
sub DESTROY {
my $self = shift;
print "destroying...\n";
$self->unmock;
}
1;
}
####
foo
Use of uninitialized value in subroutine dereference at script.pl line 30.
destroying...
baz
baz
(in cleanup) Unable to create sub named "" at script.pl line 30.
####
foo
destroying...
baz
baz
####
my $closure_self = $self;
weaken $closure_self;
$self->{sub} = \&One::foo;
*One::foo = sub { $closure_self->{x} = 'x'; return "baz\n"; };
return $self;
####
foo
baz
destroying...
foo
####
sub DESTROY {
use Data::Dump;
my $self = shift;
print "destroying...\n";
print dd($self), "\n";
$self->unmock;
}
####
foo
destroying...
bless({}, "Count")
1
baz
baz
####
foo
baz
destroying...
bless({ sub => sub { ... }, x => "x" }, "Count")
1
foo
####
sub unmock {
my $self = shift;
*One::foo = $self->{sub};
}