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

Taking a survey of the various data validation pages out there, they largely suffer from a duplication of effort of providing and interfacing to common regular expressions. Data::FormValidator, which I maintain, also has this problem. I would like to address this by interfacing D::FV with the excellent Regexp::Common package.

Strictly speaking, no glue code is necessary, because D::FV already has support for using your own regular expressions (which could be provided by Regexp::Common).

Still, some glue code could add some value in some important ways. D::FV allows you to globally turn on data untainting. R::C generally supports this as well, but with a different syntax. Also, if a constraint has a name, it's easier to use later when defining error messages for each constraint.

SO, with that background, here's the bit of glue code I'm playing with but can't get to work. What's supposed to happen is this: When a routine named: RE_net_IPv4 is requested, the following subroutine will created automatically:

sub match_RE_net_IPv4 { my $val = shift; no strict 'refs'; my $re = &RE_net_IPv4(-keep); return ($val =~ $re) ? $1 : undef; };

Initially I thought this was a case for AUTOLOAD, but the way validator_packages works in D::FV is that the symbol table is scanned for all routines with names beginning with "match_", and they are imported into the current name space.

This seems like it will be somewhat inefficient for this case, because it seems fake "match_" routines will need to be made for all Regexp::Common routines before one is ever called!

Still, I tried to do this by creating a BEGIN block that would create the @EXPORT array on the fly. Here's the code I'm working with:

package Data::FormValidator::Constraints::Common; use 5.005; use strict; require Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); @ISA = qw(Exporter); $VERSION = '0.01'; BEGIN { @EXPORT = &_build_exports_from_regexp_common; use Symbol; use Regexp::Common 'RE_ALL'; sub _build_exports_from_regexp_common { my @exports; my $package_ref = qualify_to_ref('Regexp::Common::'); my @subs = grep(/^RE_/, keys(%{*{$package_ref}})); foreach my $sub (@subs) { my $dfv_name = 'match_'.$sub; print $dfv_name; *$dfv_name = sub { my $val = shift; no strict 'refs'; my $re = &$sub(-keep); return ($val =~ $re) ? $1 : undef; }; push @exports, '&'.$dfv_name; } return @exports; } } 1;

And here's a test case to test it:

# Integration with Regexp::Common; use Test::More tests => 3; use Data::FormValidator; my %FORM = ( bad_ip => 'oops', good_ip => '127.0.0.1', ); my $results; eval { $results = Data::FormValidator->check(\%FORM, { required => [qw/good_ip bad_ip/], validator_packages => 'Data::FormValidator::Constraints::Commo +n', constraint_regexp_map => { '/_ip$/' => 'RE_net_IPv4', } }); }; warn $@ unless ok((not $@), 'runtime errors'); ok($results->('valid')->{good_ip}, 'good ip'); ok($results->('invalid')->{bad_ip}, 'bad ip');

Thanks for you help! If we can get this working well, I'll give up on adding new REs to D::FV and just add them to Regexp::Common instead. Even if something like this can't work, I think I'll better document how to use Regexp::Common RE's with Data::FormValidator.

Mark

Replies are listed 'Best First'.
Re: Integrating Data::FormValidator with Regexp::Common (solved!)
by markjugg (Curate) on May 27, 2003 at 02:33 UTC
    So to wrap this up, I finally did get this integration to happen. It wasn't by debugging the above code though. I had an "a ha" moment, and approached the problem from a different angle, and found a solution that was much easier.

    I just released this Data::FormValidator 3.1.

    Mark