Skip to content
Snippets Groups Projects
Commit 96b0e087 authored by Andy Yates's avatar Andy Yates
Browse files

Adding the scope guard which is a way we can cause code to be executed even...

Adding the scope guard which is a way we can cause code to be executed even during a die. Very useful for non-global resource cleanup operations (finally blocks)
parent 8433743e
No related branches found
No related tags found
No related merge requests found
......@@ -30,7 +30,7 @@ Bio::EnsEMBL::Utils::Scalar
=head1 SYNOPSIS
use Bio::EnsEMBL::Utils::Scalar qw(check_ref assert_ref wrap_array check_ref_can assert_ref_can assert_numeric assert_integer);
use Bio::EnsEMBL::Utils::Scalar qw(check_ref assert_ref wrap_array check_ref_can assert_ref_can assert_numeric assert_integer scope_guard);
check_ref([], 'ARRAY'); # Will return true
check_ref({}, 'ARRAY'); # Will return false
......@@ -57,6 +57,17 @@ Bio::EnsEMBL::Utils::Scalar
asssert_integer(1.1, 'dbID'); #Fails
asssert_numeric(1E-11, 'dbID'); #Passes
asssert_numeric({}, 'dbID'); #Fails
#Scope guards
my $v = 'wibble';
{
#Build a guard to reset $v to wibble
my $guard = scope_guard(sub { $v = 'wibble'});
$v = 'wobble';
warn $v; # prints wobble
}
# $guard is out of scope; sub is triggered and $v is reset
warn $v; # prints wibble
#Tags are also available for exporting
use Bio::EnsEMBL::Utils::Scalar qw(:assert); # brings in all assert methods
......@@ -94,6 +105,7 @@ our @EXPORT_OK;
check_ref check_ref_can
assert_ref assert_ref_can assert_numeric assert_integer assert_boolean assert_strand assert_file_handle
wrap_array
scope_guard
);
%EXPORT_TAGS = (
assert => [qw(assert_ref assert_ref_can assert_integer assert_numeric assert_boolean assert_strand assert_file_handle)],
......@@ -404,4 +416,43 @@ sub assert_file_handle {
return 1;
}
=head2 scope_guard
Arg [1] : CodeRef The block of code to exit once it escapes out of scope
Description : Simple subroutine which blesses your given code reference into
a L<Bio::EnsEMBL::Utils::Scalar::ScopeGuard> object. This has
a DESTROY implemented which will cause the code reference
to execute once the object goes out of scope and its reference
count hits 0.
Returntype : Bio::EnsEMBL::Utils::Scalar::ScopeGuard
Example : my $v = 'wibble';
{
#Build a guard to reset $v to wibble
my $guard = scope_guard(sub { $v = 'wibble'});
$v = 'wobble';
warn $v;
}
# $guard is out of scope; sub is triggered and $v is reset
warn $v;
Exceptions : Raised if argument was not a CodeRef
Status : Stable
=cut
sub scope_guard {
my ($callback) = @_;
assert_ref($callback, 'CODE', 'callback');
return bless($callback, 'Bio::EnsEMBL::Utils::Scalar::ScopeGuard');
}
1;
#### SUPER SECRET PACKAGE. IGNORE ME
package Bio::EnsEMBL::Utils::Scalar::ScopeGuard;
sub DESTROY {
my ($self) = @_;
$self->();
return;
}
1;
......@@ -132,4 +132,31 @@ lives_ok { assert_file_handle($other_scalar_fh) } 'Passing in a blessed scalar F
lives_ok { assert_file_handle($io_handle) } 'Passing in an IO::Handle means lives';
close($_) for ($scalar_fh, $other_scalar_fh);
#Scope Guard
#First normal circumstances
{
my $v = 'wibble';
is($v, 'wibble', 'Value is normal');
{
my $guard = scope_guard(sub { $v = 'wibble'});
$v = 'wobble';
is($v, 'wobble', 'Value has been changed');
}
is($v, 'wibble', 'Value has been reset');
}
#With a die; Perl respects DESTROY even if we are in the middle of SIG{__DIE__}
{
my $v = 'wibble';
is($v, 'wibble', 'Value is normal');
$v = 'wobble';
is($v, 'wobble', 'Value has been changed');
eval {
my $guard = scope_guard(sub { $v = 'wibble'});
die 'we have died';
};
is($v, 'wibble', 'Value has been reset even after a die');
}
done_testing();
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment