I have tried a number of approaches to this error checking
problem. None of them completely satisfied me. But for
the moment here is the one that seems to work best.
What I do is having a function that does destructive
manipulation of my arguments:
# Takes a hashref, a key name, and an optional default.
# Removes that key from the hash, and returns the value or
# the default. Blows up if there is no value or default.
sub excise_arg {
my $args = shift;
my $arg_name = shift;
if (exists $args->{$arg_name}) {
return delete $args->{$arg_name};
}
elsif (@_) {
return shift;
}
else {
confess("Missing required argument '$arg_name'");
}
}
Call it without a default argument and you have a required
key. Put in the default and it is optional. And since it
is destructive, it gets rid of the keys and I can use this
for a typo check.
# Takes a hashref. Verifies that it is empty
sub assert_args_done {
my @left = keys %{ $_[0] };
if (@left) {
confess("Unexpected arguments '@left' left over");
}
}
And now in a function I can do this:
sub some_func {
my $args = { @_ };
my $name = excise_arg($args, 'name'); # required
my $age = excise_arg($args, 'age', undef); # optional
assert_args_done($args);
# Rest of the code here.
}
And if I want to take an existing function and wrap it in
one that can handle some things itself and wraps the rest,
it is easy. I just excise a few arguments and then pass
the rest through untested. As long as they are tested
somewhere, typos get checked.
If anyone has alternate suggestions for how to handle
this problem, I am open. This seems to work pretty well,
but I have tried several things, and I don't claim that
this is perfect.
UPDATE
Thanks Hofmator for catching my obvious typo. That is
what I get for typing something up off of the top of my
head. That is also why I use strict. :-)