On Oct 11, 2011, at 10:30 AM, Peter Gordon wrote:
> I am trying to find a decent design pattern for Moose validation of
> user input. All the Moose examples I have found either assume that 
> the data is correct or else dies.
> 
> Example:
> package Address ;
> use Moose;
> use Moose::Util::TypeConstraints;
> 
> subtype 'Email',
>      as 'Str',
>      where { $_ =~ m!@! },
>      message { "The email you provided, $_, was not a valid email" };
> 
> package Person ; 
> use Moose ; 
> has 'email' => (is => 'rw', isa => 'Email', required => 1) ;
> 
> package main ;
> 
> my $f = Person->new(email => 'xa.com') ; 
> 
> The above pattern is much like the examples in the manual. 
> 
>> From an OOP perspective, it seems to me that the validation performed
> by the subtype should be part of the class and not something that is
> just floating around. There is also no reasonable way to trap the
> error, and report back to the user that there was an error. And I am
> not a fan of try/catch.
> 
> I have come up with the following design pattern to allow validation.
> The idea is to create a class, Email, which accepts any data. If the
> data is good, error is set to 0.  If the error is set to 1, it also
> changes the package name so that if it is passed onwards the program
> dies.
> 
> package EmailRole ; 
> use Moose::Role ; 
> 
> has 'email' => ( is => 'rw', isa => 'Str',required => 1) ;   
> has 'error' => ( is => 'rw', isa => 'Str', default => 0) ;   
> 
> sub BUILD { 
>    my $my = shift ;
>    if ($my->email !~ m!@!) { 
>        $my->error(1) ; 
>        bless $my, 'EmailError'; 
>    } 
>    return $my ;
> } 
> no Moose ; 
> 
> package Email ;
> use Moose ; 
> with 'EmailRole' ; 
> 
> package EmailError ;
> use Moose ; 
> with 'EmailRole'; 
> 
> no Moose ; 
> 
> package Person ; 
> use Moose ; 
> has 'email' => ( is => 'ro', isa => 'Email' ) ; 
> 
> package main ; 
> my $emailGood = Email->new(email => 'x...@yyy.com') ;
> my $personGood = Person->new(email => $emailGood) ;
> 
> my $emailBad = Email->new(email => 'xxx') ; 
> print "Bad Person" if $emailBad->error ; 
> # And if we insist on proceeding, the following line will fail.
> my $personBad = Person->new(email => $emailBad) ;
> 
> What I would like is some feedback 
> a) what are the pitfalls of this design.
> b) are there any better designs?
> 

Peter,

Validation is different then type checking, which is why you are running into 
this issue. Putting the validation in the type allows a certain kind of re-use 
that goes beyond just using it in a class. Remember that Moose types are 
themselves objects which you can call methods on, etc.

I recommend looking at something like Data::Manager 
(https://www.metacpan.org/module/Data::Manager) or the lower level 
Data::Verifier (https://www.metacpan.org/module/Data::Verifier) which will 
allow you to use Moose types to test things and capture errors effectively. It 
also is a great illustration of using Moose types in a totally different 
context.

- Stevan








Reply via email to