Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re: Re: Re: RFC - Parameter Objects

by Corion (Patriarch)
on May 14, 2003 at 19:10 UTC ( [id://258211]=note: print w/replies, xml ) Need Help??


in reply to Re: Re: RFC - Parameter Objects
in thread RFC - Parameter Objects

While this is nice and convenient for those cases where you have independently valid parameters, it's impossible (or dangerous, you choose) to have pairs (or more) of parameters that are valid together :

my $ratio = Sub::ParamObject->new({ nominator => qr/^[-+]?\d+$/, denominator => sub { $_[1] =~ qr/^\d+$/ and $_[1] != 0 }, }); # works and is convenient $ratio->nominator(-1); $ratio->denominator(1); my $source = Sub::ParamObject->new({ selector => qr/^filename|url$/, filename => sub {$_->[0]->{selector} eq 'filename' and $_[1] =~ +qr/^\w+$/ }, url => $_->[0]->{selector} eq 'filename' and $_[1] =~ qr!^h +ttps?://!i }, }); # and now ??? # I want to have selector set to one of the values # and (only) the corresponding field set. $source->selector('filename')->filename('foo.txt'); # works $source->filename('foo.txt')->selector('filename'); # cannot in my i +mplementation

Either you make the approach dependent on the order of parameters (plausible but ugly IMO), or you find another approach to validation (which I would rather welcome, since I did stuff like this years ago and didn't find a good solution to this).

perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web

Replies are listed 'Best First'.
Re(4): RFC - Parameter Objects (validation)
by Ovid (Cardinal) on May 14, 2003 at 20:33 UTC

    Making the approach dependent on the order in which the mutators is called would be ugly. It would also be bug prone. Forget it just once and you might be wondering why the heck your code is misbehaving.

    Perhaps the contructor could be modified. The current hashref would fall under a key named "params" and a different key named "groups" would list group validations. Then, as soon as an accessor is called, the "group" validations would be checked. This would eliminate the order dependence. Workable?

    Cheers,
    Ovid

    New address of my CGI Course.
    Silence is Evil (feel free to copy and distribute widely - note copyright text)

      Perhaps the contructor could be modified. The current hashref would fall under a key named "params" and a different key named "groups" would list group validations. Then, as soon as an accessor is called, the "group" validations would be checked. This would eliminate the order dependence. Workable?

      This still leaves it up to the person constructing the Params object ot specify what the overall validation function is ... maybe the %params hash is some global that gets re-used by all of the clients -- because if they don't then the method they are passing the Params too will fail when it tries to access things with a certian name -- but they can allways just choose to not pass a "groups" test and circumvent the tests.

      I would recommend approaching this problem form a different direction -- seperate the "definition" of what a valid Param object is for a given context, from the "instantiation" of a particular instance.

      Consider something like this...

      #### in the library code ### Sub::Param::make_new_param_type($param_type_name \%param_definitions, \&validity_function); ... sub some_method { my $param = shift; die "die" unless $param->isValid($param_type_name); ... } sub some_other_method { my $param = shift; die "die" unless $param->isValid($param_type_name); ... } ... ### in some client ... my $p = new Sub::Param($param_type_name); $p->foo(1); $p->bar('Toledo'); SomeLibrary::some_method($p); ...
Re^4: RFC - Parameter Objects (dependencies are problematic)
by Aristotle (Chancellor) on May 21, 2003 at 14:26 UTC
    The problem here is that your validation code assumes a certain order.
    my $source = Sub::ParamObject->new({ selector => sub { my $self = shift; return unless $_[0] =~ /^(filename|url)$/; return if @$self{qw(filename url)} and !exists $self->{$1}; }, filename => sub { my $self = shift; return (!exists $self->{selector} or $self->{selector} eq 'filename +') and $_[1] =~ qr/^\w+$/; }, url => sub { my $self = shift; return (!exists $self->{selector} or $self->{selector} eq 'url') and $_[1] =~ qr!^https?://!i }, });
    If you squint a bit you'll notice two levels of validation: one is of the value as such, and one is of the dependencies. This can be condensed and clarified by allowing multiple tests:
    my $source = Sub::ParamObject->new({ selector => [ qr/^(filename|url)$/, sub { @{$_[0]}{qw(filename url +)} and !exists $self->{$_[1]} }, ], filename => [ qr/^\w+$/, sub { !exists $_[0]->{filename} or $_[0]- +>{selector} eq 'url' }, ], url => [ qr!^https?://!i, sub { !exists $_[0]->{filename} or $_[0] +->{selector} eq 'url' }, ], });
    Getting the order right however is bound to get tricky for large parameter sets. That's a problem which can only be expressed well with the semantics of a logical programming language such as Prolog or make. The fundamental obstacle with order-dependent validation is that you need to change the validity of things based on that of others. You might try something like this:
    my $source = Sub::ParamObject->new(test => { selector => { value => qr/^(filename|url)$/, }, filename => { value => qr/^\w+$/, }, url => { value => qr!^https?://!i, }, }, if_valid => { selector => sub { $_[0]->add_check($_[1] eq 'url' ? 'filename' : 'url', forbidde +n => sub { return }); }, filename => sub { $_[0]->add_check(selector => need_filename => sub { $_[1] ne ' +url' }); }, url => sub { $_[0]->add_check(selector => need_url => sub { $_[1] ne 'filen +ame' }); }, });
    I used a hash of hashes here so checks can also easily be removed by a ->remove_check(). Even this is likely to become a maze of little tests, all alike, for large parameter sets, though.

    Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://258211]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (2)
As of 2024-04-19 00:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found