I fixed a bug in some under-tested code yesterday while writing unit tests.
package Some::Module
{
use Modern::Perl;
use Moose;
# Moose attributes here
sub some_useful_method
{
my ($self, $value) = @_;
my $scrubbed_value = Some::Helper::some_function( $value );
$self->set_value( $scrubbed_value );
}
}
The details aren't interesting, but this is the minimal example necessary to show the problem. If you don't immediately see it, here's an alternate version of the method which would have made the error obvious:
sub some_useful_method
{
my ($self, $value) = @_;
my $scrubbed_value = some_function( $value );
$self->set_value( $scrubbed_value );
}
In this case, the desire not to pollute the current namespace with
auxiliary functions defined elsewhere was the culprit. The solution was to add
a single use Some::Helper;
to the file.
Unfortunately, there was no way to catch this without writing a test which exercised the code path which triggered this call. The discipline of comprehensive testing would have caught it, as would the practice of importing functions from other packages explicitly. Couple that with namespace::autoclean to alleviate namespace pollution (thanks, Python!) and the damage is minimal, as long as everyone working on this code demonstrated sufficient discipline.
Then again, I can imagine a Perl 5 pragma which attempts to resolve all such
symbols, qualified and not, at the end of compile-time and aborts the program
otherwise. (Yes, there are AUTOLOAD
concerns, but those are
tractable.)
Sometimes a little more static typing up front can be useful.
Do you know about http://search.cpan.org/~thaljef/Perl-Critic-Dynamic-0.04/lib/Perl/Critic/Policy/Dynamic/ValidateAgainstSymbolTable.pm?
Does CPAN's B::LintSubs help you perhaps?