Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Moose: checking parms in object construction

by Marshall (Canon)
on Aug 02, 2017 at 03:49 UTC ( [id://1196502]=perlquestion: print w/replies, xml ) Need Help??

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

I am a complete newbie to Moose.
I would appreciate some help with what a I hope is a "simple" Moose problem.
The code below "works".
But I want to enhance it so that the new() method for Appointment will throw an exception or otherwise report an error if the parameters don't "jive" when taken into context amoungst each other. In addition, is there any easy way to say limit the Month parameter to between 1 and 12? I can see that 'Int' works, but is it possibile to be more specific in the limitation?

FILE:test.pl

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use Appointment; my $x = Appointment->new(Month=>45, Day => 1); print "Month: ",$x->Month,"\n"; print Dumper $x; __END__ Prints: Month: 45 $VAR1 = bless( { 'Day' => 1, 'Month' => 45, 'Freq' => 'OneTime' }, 'Appointment' );
FILE: Appointment.pm
#!/usr/bin/perl #file: Appointment.pm package Appointment; use Moose; # automatically turns on strict and warnings my @freq_valid = (qw/OneTime Daily Monthly Quarterly/); has 'Month' => ( is => 'ro', isa => 'Int', required => 1, ); has 'Day' => ( is => 'ro', isa => 'Int', required => 1, ); has 'Freq' => ( is => 'ro', isa => 'Str', default => 'OneTime', ); 1;
Update: I have found the replies by kevbot++ and Your Mother++ to be extremely helpful. Thanks!

Replies are listed 'Best First'.
Re: Moose: checking parms in object construction
by Your Mother (Archbishop) on Aug 02, 2017 at 05:01 UTC

    Before you trudge all the way down Moose Avenue, give Moo a chance. It’s faster, has fewer deps and, to me, has easier semantics and with the Type::Tiny family, it is super powerful. Note the problem with leap years and the 29th in the implementation I offer.

    package Appointment 0.01 { use Moo; use Types::Standard qw/ Int Enum /; use Date::Calc qw/ Today_and_Now check_date /; use Carp; has month => is => "ro", isa => Int, required => 1, ; has day => is => "ro", isa => Int, required => 1, ; has freq => is => "ro", isa => Enum[qw/ OneTime Daily Monthly Quarterly /], default => sub { "OneTime" } ; sub BUILD { my ( $self, $args ) = @_; my @check = ( [ Today_and_Now ]->[0], $self->{month}, $self->{ +day} ); croak sprintf("Date is invalid for this year: %4d-%02d-%02d", +@check) unless check_date(@check); } }; 1; # <-- Update, return true.
Re: Moose: checking parms in object construction
by kevbot (Vicar) on Aug 02, 2017 at 04:28 UTC
    Hello Marshall,

    You can use types to constrain the values of attributes, see Moose::Manual::Types and Moose::Util::TypeConstraints. For example, you could use an anonymous type to ensure that the value of Month is between 1 and 12.

    If you need to perform more complex checking of your arguments, then you can define a BUILD method (see Moose::Manual::Construction).
    package Appointment; use Moose; # automatically turns on strict and warnings use Moose::Util::TypeConstraints; my @freq_valid = (qw/OneTime Daily Monthly Quarterly/); has 'Month' => ( is => 'ro', isa => subtype( 'Int' => where { $_ > 0 and $_ < 13 +} ), required => 1, ); has 'Day' => ( is => 'ro', isa => 'Int', required => 1, ); has 'Freq' => ( is => 'ro', isa => 'Str', default => 'OneTime', ); sub BUILD { my $self = shift; if ($self->Month == 12 and $self->Day == 1){ die "I'm having a bad Moose day."; } } 1;
    UPDATE: Here is an example of using a subtype to check the values of your Freq attribute.
    package Appointment; use Moose; # automatically turns on strict and warnings use Moose::Util::TypeConstraints; use List::Util qw/any/; my @freq_valid = (qw/OneTime Daily Monthly Quarterly/); subtype 'AppointmentFreq' => as 'Str' => where { my $arg = $_; any{ $_ eq $arg } @freq_valid } => message { 'The Freq you provided is not valid' }; has 'Month' => ( is => 'ro', isa => subtype( 'Int' => where { $_ > 0 and $_ < 13 +} ), required => 1, ); has 'Day' => ( is => 'ro', isa => 'Int', required => 1, ); has 'Freq' => ( is => 'ro', isa => 'AppointmentFreq', default => 'OneTime', ); sub BUILD { my $self = shift; if ($self->Month == 12 and $self->Day == 1){ die "I'm having a bad Moose day."; } } 1;

Log In?
Username:
Password:

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

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

    No recent polls found