Filter::Cleanup
Filter::Cleanup provides a simple way to deal with cleaning up after multiple
error conditions modeled after the D programming language's scope(exit)
mechanism.
Each cleanup block operates in essentially the same manner as a finally
block in languages supporting try/catch/finally style error handling.
cleanup blocks may be placed anywhere in a scope. All statements lexically
scoped after the cleanup block will be wrapped in an eval. Should an error
be triggered within the block, the cleanup statement will be called before
any error is rethrown (using croak).
Within the cleanup block, the status of $@ may be inspected normally.
Multiple cleanup blocks stack, and each MUST be followed by a semi-colon
to ensure proper organization of the outputted code. cleanups are executed
in reverse order (it's a stack, see?) and may be nested, although this defeats
the purpose. The reason for reverse execution is that each cleanup represents
another nested level of evals and clean-up code.
Take the following code:
use Filter::Cleanup;
sub example {
cleanup { print "FOO" };
print "BAR";
return 1;
}
This is roughly the output of the source filter:
sub example {
my $result = eval {
print "BAR";
return 1;
};
my $error = $@;
print "FOO";
if ($error) {
croak $error;
} else {
$result; # returns 1
}
}
Now with multiple cleanups:
use Filter::Cleanup;
sub example {
cleanup { print "FOO" };
cleanup { print "BAZ" };
print "BAR";
return 1;
}
The following code would be generated:
sub example {
my $result = eval {
my $result = eval {
print "BAR";
return 1;
};
my $error = $@;
print "BAZ";
if ($error) {
croak $error;
} else {
$result;
}
};
my $error = $@;
print "FOO";
if ($error) {
croak $error;
} else {
$result; # returns 1
}
}
Internally, PPI is used to parse the module and generate the new code. This is
because there are so many different forms which could proceed a cleanup block
that there is no more efficient way to ensure that valid code is emitted. PPI
has proven to be stable, robust, and very reasonably efficient.
MODIFYING RETURN VARIABLES WITHIN A CLEANUP BLOCK
This can sometimes have surprising results due to the manner in which cleanup
blocks are evaluated. By the time the cleanup block executes, the result of
evaluating the protected code has already been determined and stored. Cleanup
blocks are then processed, and their results are discarded after being inspected
for errors. Therefore, something like this:
sub test {
my @words = ('foo');
cleanup { push @words, 'bat' };
cleanup { push @words, 'baz' };
cleanup { push @words, 'bar' };
return @words;
}
...will cause 'foo' to be returned, because @words has not been modified by the
time the return value is calculated.
In order to effect changes in return values in cleanup (a questionable
practice, but hey, I don't judge), a reference is required:
sub test {
my $words = ['foo'];
cleanup { push @$words, 'bat' };
cleanup { push @$words, 'baz' };
cleanup { push @$words, 'bar' };
return $words;
}
The above code will return ['foo', 'bar', 'baz', 'bat'].
INSTALLATION
To install this module, run the following commands:
perl Makefile.PL
make
make test
make install
SUPPORT AND DOCUMENTATION
After installing, you can find documentation for this module with the
perldoc command.
perldoc Filter::Cleanup
You can also look for information at:
RT, CPAN's request tracker (report bugs here)
http://rt.cpan.org/NoAuth/Bugs.html?Dist=Filter-Cleanup
AnnoCPAN, Annotated CPAN documentation
http://annocpan.org/dist/Filter-Cleanup
CPAN Ratings
http://cpanratings.perl.org/d/Filter-Cleanup
Search CPAN
http://search.cpan.org/dist/Filter-Cleanup/
LICENSE AND COPYRIGHT
Copyright (C) 2012 "Jeff Ober"
This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.