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. |