Subject: | Use Error to throw validation exceptions |
I'd like Params::Validate to throw exceptions a la Error::Simple
(see the "Error" module). The problem I face is that I cannot simply
say:
use Error;
Params::Validate::validation_options(
on_fail => sub { throw Error::Simple($_[0]); }
);
since this would report the exception happening in the
anonymous sub, and not in the real place (i.e. the
sub where validate(...) was called).
A quick hack (see below) solves the problem, but has the disadvantage
that it does not work when validate is called in an anonymous sub - i did
not find a simple way how to determine the real calling sub in that
context. Note that the caller stack looks rather different when the
validate call is in a "try { ... }" block or not - which means I
cannot use a constant value for caller(). Here is a sample script
(using latest Params::Validate and Error):
#!/usr/bin/perl -w
use strict;
use Error qw(:try);
use Params::Validate qw(validate_pos);
#######################################################################
# THE FOLLOWING COULD BE AN EXTENSION FOR PARAMS::VALIDATE
#######################################################################
package Error::Params::Validate;
@Error::Params::Validate::ISA = qw(Error);
sub new {
my ($self, $msg) = @_;
my ($pack,$file,$line,$sub);
my $i = 0;
do {
($pack,$file,$line,$sub) = caller(++$i);
#print "DEBUG: p=$pack f=$file l=$line s=$sub\n";
} while($pack =~ /^Error::/ || $sub =~ /^Error::|__ANON__$/);
chomp $msg;
$msg =~ s/\S+::__ANON__\b/$sub/;
local $Error::Depth = $Error::Depth + 1;
$self->SUPER::new(-text => $msg, -file => $file, -line => $line, '-package' => $pack)
}
sub stringify {
my $self = shift;
my $text = $self->SUPER::stringify;
$text .= sprintf(" at %s line %d.\n", $self->file, $self->line)
unless($text =~ /\n$/s);
$text;
}
#######################################################################
# END (THE FOLLOWING COULD BE AN EXTENSION FOR PARAMS::VALIDATE)
#######################################################################
package main;
Params::Validate::validation_options(
on_fail => sub {
throw Error::Params::Validate $_[0];
}
);
mysub('foobar');
mysub2('foobar');
exit 0;
sub mysub
{
my @par = @_;
try {
validate_pos( @par, 1, 1 );
} catch Error::Params::Validate with {
my $E = shift;
print "ERROR:\n";
foreach(sort keys %$E) {
print " $_ => ",$E->{$_},"\n";
}
};
print "mysub GOT: +$_[0]+\n";
}
sub mysub2
{
my @par = @_;
validate_pos( @par, 1, 1 );
print "mysub2 GOT: +$_[0]+\n";
}
__END__
I think the best would be if one could specify sth. like
Params::Validate::validation_options(
on_fail_throw => 'Error::Params::Validate' }
);
or the like... and of course it has to work if the "validate" call
is in a try { ... } block or not.
By the way: the Params::Validate manual contains this:
* on_fail => $callback
If given, this callback will be called whenever a valĀ
idation check fails. It will be called with a single
parameter, which will be a string describing the failĀ
ure. This is useful if you wish to have this module
throw exceptions as objects rather than as strings,
for example.
I missed an example here - maybe everything is very simple and I
just did not get it.
Best regards,
Marek