سؤال

In my Perl script, I have subroutine that is called hundreds of times with as many different sets of parameters, as the only values that are sent in are ones that differ from the defaults. (It goes without saying that the number of permutations and combinations is very large) To make it more robust, I would like to do some checking on the parameters. Here is a shrunken version of my subroutine (the actual version has dozens of parameters with very specific, sometimes lengthy names):

# Obtain any parameters that differ from the defaults and send for processing
sub importantSub
{
   my %params = 
   (
      commandType       => 5,
      commandId         => 38,
      channel1Enable    => 0,
      channel2Enable    => 0,
      channel3Enable    => 0,
      channel4Enable    => 0,
      channel5Enable    => 0,
      channel6Enable    => 0,
      channel7Enable    => 0,
      channel8Enable    => 0,
      channel9Enable    => 0,
      channel10Enable   => 0,
      # This goes on for a VERY long time
      @_
   );

    # Make sure we have exactly as many keys as we expect - verify that
    # no additional parameters were added (Real version has 92)
   if( keys(%params) !=  92 ) 
   {
      croak("Unexpected parameter in hash!");
   }

   return &$privateProcessingFunction('Data Path Configuration', \%params);
}

As you can see, I currently do a check to see if the number of values is the same, as if something is sent in as "chan1Enable" instead of "channel1Enable", it will throw that number off.

But with so many calls to the subroutine from multiple other scripts written by multiple other engineers, I would like to find a way to find WHICH value was incorrect (e.g. Don't just say that there was an unexpected parameter, say that "chan1Enable" was invalid). Furthermore, if multiple values were incorrect, I'd like to list all of them.

What is the most efficient way to do this?

(I ask about efficiency since the function is currently called in over 400 different ways and that will likely continue to grow as the application expands.)

هل كانت مفيدة؟

المحلول

There are two kinds of errors: supplying an unrecognized parameter, or failing to supply a recognized parameter. You'll have to worry about the second issue as you edit the list of parameters and make sure that the new parameters are used consistently throughout the application.

The best and easiest solution is to use another hash.

my @params = qw(commandType commandId channel1Enabled ...);
my %copy = %params;
my @validation_errors = ();

# are all the required parameters present?
foreach my $param (@params) {
    if (not exists $copy{$param}) {
        push @validation_errors, "Required param '$param' is missing.";
    }
    delete $copy{$param};
}

# since we have  delete'd  all the recognized parameters,
# anything left is unrecognized
foreach my $param (keys %copy) {
    push @validation_errors, "Unrecognized param '$param' = '$copy{$param}' in input.";
}

if (@validation_errors) {
    die "errors in input:\n", join("\n", @validation_errors);
}

نصائح أخرى

I recommend using a formal tool to help validate your parameters your passing in. Params::Validate is tried and true, while Type::Params is a recent take on the problem space, allowing you to use same set of constraints that you would also use with Moo or Moose.

Here's the kind of diagnostic that Params::Validate would give you for an unrecognized parameter:

use Params::Validate ':all';

sub foo {
    my %p = validate(@_, {
        first_required => 1,
        second_required => 1,
        first_optional => 0.
    });
}

foo( boom => 'zoom' );

Results in:

The following parameter was passed in the call to main::foo but was not listed in the validation options: boom
 at /tmp/t.pl line 7
        main::foo('boom', 'zoom') called at /tmp/t.pl line 14
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top