thekestrel has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,
I'm Reading Randal's, Perl Object, References & Modules which I just got and am using it to convert my 'stuff a Package keyword at the top and change the .pl to .pm' style package to be CPAN compliant (Great book btw for those who haven't read it yet).
Things are moving along quite nicely and I have a large number of cases to test the things that should work and even the middle as Randal refers to it (using the make test (t/*.t) ). Now I'm trying to test the edges and make sure that the things that should not, do not and I'm looking to bolster the initial code in my interface subroutines such that they are not phased by boundary conditions. This made me realize that my code itself does not check for many boundary conditions and as such I'd like to fix that.

The three types of cases I want to cover are;
1) Insufficient arguments
2) Too many arguments
3) Bad argument types

What I'm looking for is the most minimal code such that you can achieve something like this; i.e.

sub Func1 { do we have a num_var; do we have a name_var; do we have params (optional) is the num_var of number format is the name_var of name format .... other code } Func1($num_var, $name_var, %params);
I know this is a little generic, but lets say most subroutines can take a generic number style argument and others take a generic string type argument I want to make sure thats all they are.
This will no doubt take the form of a reg exp checking its just a string (i.e. no :;"' etc. in it) and similarly for the number.
I'm sure there are *many* well written modules that take care of boundary conditions so what I'm wanting is the 'standard' code for doing these 'generic' tests so to speak i.e. the best practice bit of code for doing this? Do people generally generally just go;
Func1 { is number of args correct? check arg1 is a number and only a number with reg exp? check arg2 is a string and only a string with reg exp? ... other code }
or are there more elegant solutions that are generally used...something like?
sub CheckArgs { get number of args get args to check check we have the right number of args foreach arg check the type with the appropriate reg exp. return status. } sub Func1 { CheckArgs (2, @_, "NUM", "STRING"); .... other code } sub Func2 { CheckArgs (3, @_, "STRING", "NUM", "STRING"); .... other code }

Is the second sort of approach considered to weighty if you are wanting the code to be quite fast or is just checking each argument individually in each subroutine generally the practice as in there are no 'generic' inputs? I would appreciate any insights or code snippits on how others have satisfied boundary conditions.

Regards Paul.
Update: If you want an example subroutine to write something around here is one...
In this case it would just be $name that would need to be checked, and that we have a name...I'm just trying to think generically though.
sub add_output { #Create an unconnected named output my $self = shift; my $graph = $self->{graph}; my $name = shift; my %params = @_; #Check for valid options foreach my $p ( keys %params ) { if ( !exists $valid_userconfigurable_vertex_params->{$p} ) { Carp::confess(sprintf "Unknown Option : $p"); } } #Set the activation function my $activation; if ( exists $params{activation} ) { $activation = $params{activation}; } else { $activation = "SIGMOID"; } #Create the vertex $graph->set_vertex_attributes($name, { id => GetNewVertexNumb +er($self), added_a_vertex => 1, allow_inputs => "Yes", allow_outputs => "No", activation => $activat +ion, value => 0 }); #Connect vertex to the bias vertex $graph->add_edge("BIAS", $name); #An update to the layout is required $graph->set_graph_attribute("update_layout", 1); }

2005-03-30 Janitored by Arunbear - added readmore tags, as per Monastery guidelines

Replies are listed 'Best First'.
Re: Testing Edges
by dragonchild (Archbishop) on Mar 29, 2005 at 18:25 UTC
    Params::Validate

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      Dragonchild,
      Thanks for the link, that pretty much looks like exactly what I was after. =)

      Regards Paul
      Dragonchild,
      I've been tinkering with it for a while, but don't seem to be having much luck with positional arguments as opposed to named ones. Named parameters seem to be working fine, I just don't seem to do anything, but check for existence of positional arguments.
      Just prior to the 'Dependancies' section on the documentation of the module it says....

      or this for positional parameters: validate_pos( @_, { type => SCALAR }, { type => ARRAYREF, optional => + 1 } ); By default, parameters are assumed to be mandatory unless specified as + optional.
      However, if I enter something like this...
      #!/usr/bin/perl #use strict; use warnings; use Params::Validate; sub func1 { validate_pos( @_, { type => SCALAR} ); print "hi fluffy\n"; } func1("test");
      I get the following...
      Argument "SCALAR" isn't numeric in subroutine entry at ./a.pl line 8. Parameter #1 ("test") to main::func1 was a 'scalar', which is not one +of the allowed types: at ./a.pl line 8 main::func1(3) called at ./a.pl line 13
      Any ideas why this is so? Ideas....?

      Regards Paul
        You need to
        use Params::Validate qw(:types);
        to get the constants used for type checking (the SCALAR in your example).

        Params::Validate docs

        - Espen
Re: Testing Edges
by Tanktalus (Canon) on Mar 29, 2005 at 18:00 UTC

    One of the cool things in perl, to me, is the fact that perl often does what I mean, even if the author of the subroutine didn't intend for it. For example, in the thread "Should Modules Do I/O?", there's a deep question about writing directly to files. One of the solutions is to write to a filehandle. Now, the really pedantic may check that the file handle given actually is a GLOB, or may instead check that it's an IO::Handle. But what if I, instead, created my own object that did something truly funky, and implemented all the functions that you call, which did some other sort of magic to the data? It may not be derived from IO::Handle, but it works just fine!

    Or maybe you want to take a callback function. If at all possible, use the $object->$function(@params) syntax for callbacks - this allows an incredible amount of flexibility. I can give you a function name (string), or I can give you a code-ref. And your code will just work... and so will mine.

    My point is to be very careful about what you validate. Sometimes you need to validate, but other times you're just getting in the way of the natural, perlish flexibility of your function.

Re: Testing Edges
by ikegami (Patriarch) on Mar 29, 2005 at 17:44 UTC

    In addition to "STRING" and "NUM", you could also accept a sub ref. That will allow custom validators. For that matter, you could create a constant called STRING containing a refs to the string validation sub. Same for NUM.

    How do you plan to handle "a string or undef"? I imagine that's a common case.