Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

accessor generation with constraints

by szabgab (Priest)
on Oct 09, 2007 at 10:21 UTC ( [id://643657]=perlquestion: print w/replies, xml ) Need Help??

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

When creating a class quickly I often use Class::Accessor but this time I have many setters that need to validate the values passed to them. I have implemented a simple case when using regular expressions for validations but I already know I have other setters that will need to check against a fixed set of values and then who knows what else.
package MyClass; use base qw(Class::Accessor); sub set { my ($self, $field, $value) = @_; my %VALID = ( fname => qr/^[\w-]+$/, ); if (defined $VALID{$field}) { if (ref $VALID{$field} eq 'Regexp') { if ($value =~ $VALID{$field}) { $self->{$field} = $value; } else { die "Invalid value '$value'\n"; } } else { die "Unknown VALIDATOR"; } } } __PACKAGE__->mk_accessors(qw(fname));
I don't want to reinvent the wheel and I guess someone has implemented something like this, I just could not find it yet on CPAN.

Replies are listed 'Best First'.
Re: accessor generation with constraints
by lima1 (Curate) on Oct 09, 2007 at 13:57 UTC
    Your solution looks ok in my eyes. What's the problem? Adding enums is just another if statement (Update: when you want to implement them as described and not as a regex like qr{\A(?:red|green)\z}xms). For more exotic types just override the mutator, like the email example in the documentation:
    # Only accept addresses which look valid. sub email { my($self) = shift; my($email) = @_; if( @_ ) { # Setting require Email::Valid; unless( Email::Valid->address($email) ) { carp("$email doesn’t look like a valid address."); return; } } return $self->SUPER::email(@_); }
    I think if you are happy with Class::Accessor, use it. I don't think you would save much lines of code with any other module.
Re: accessor generation with constraints
by stvn (Monsignor) on Oct 09, 2007 at 20:01 UTC

    Moose can take care of this kind of thing very easily. Here is a simple translation of what you did.

    package MyClass; use Moose; use Moose::Util::TypeConstraints; has 'fname' => ( is => 'rw', isa => subtype('Str', where { /^[\w-]+$/ }), );
    The 'isa' becomes a anon-subtype of "Str" (the String type in Moose) but with the additional validtion in the where clause. A better way to do this though would be make it an official subtype, so that you can then re-use it in other attribute accessors.
    package MyClass; use Moose; use Moose::Util::TypeConstraints; subtype 'StringWithDashes' => as 'Str' => where { /^[\w-]+$/ }; has 'fname' => ( is => 'rw', isa => 'StringWithDashes' ); has 'lname' => ( is => 'rw', isa => 'StringWithDashes' );
    Moose can also handle delegating the validation as well, this would match the example of one of the other posters.
    use Email::Valid; has 'email' => ( is => 'rw', isa => subtype('Str', where { Email::Valid->address($_) }) );
    Of course this only barely scratches the surface of accessor validation in Moose. You can also set attributes to be required in the constructor, you can set defaults for those attributes as well. Then you can get into coercion, which allows you to easily convert one value into another. The Moose::Cookbook has examples for all these things. And if you want to extend those same types and use them in method validation as well, there is the more lightweight MooseX::Params::Validate and the more featureful MooseX::Method to choose from.

    -stvn
Re: accessor generation with constraints
by TOD (Friar) on Oct 09, 2007 at 12:15 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://643657]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (2)
As of 2024-04-25 02:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found