Question

I have the following propertiy on Moose class

package myPackage;
 use Moose;

has Number => (
  is  => 'rw',
  isa => Num,

 );

is there an option with Moose to constraint this type to float number from 0to 100 and if someone try to insert number not on the range of 0 -100 then the value will be undef if yes how can i achieve it ?

Was it helpful?

Solution

This seems to do as requested...

{
  package MyPackage;
  use Moose;
  use Types::Standard qw( Maybe Num );
  use Types::Numbers qw( NumRange );

  has n => (
    is     => 'rw',
    isa    => (Maybe[ NumRange[0,100] ])->plus_coercions(Num, sub { undef }),
    coerce => 1,
  );
}

print MyPackage->new( n =>  99 )->dump;
print MyPackage->new( n => 100 )->dump;
print MyPackage->new( n => 101 )->dump;

Update: a few explanations...

This is a type constraint for a number between 0 and 100:

NumRange[0,100]

Wrapping it with Maybe[...] allows undef to be accepted as a value:

Maybe[ NumRange[0,100] ]

Now we need to call a method on the type constraint object returned by that expression. The "obvious" Maybe[...]->methodname won't work because of the precedence of the -> operator (it would try to call the method on the arrayref, and pass the result to Maybe). So we need to provide some parentheses to do the method call (Maybe[...])->methodname.

The method we'll be calling is plus_coercions, defined in Type::Tiny (the underlying type constraint library used by both Types::Standard and Types::Numbers). This creates a new subtype of Maybe[NumRange[0,100]] but adding some coercions to it.

The coercion we add is:

Num, sub { undef }

... which means "if the value to be coerced is a number, run this sub and use its output". In the sub we don't need to check if the value being coerced is outside the 0..100 range because coercions will only be triggered if the value fails the Maybe[NumRange[0,100]] type constraint.

In fact, we could also express it like this:

(Maybe[ NumRange[0,100] ])->plus_coercions(Num, 'undef')

... using a string of Perl code instead of a sub. This is perhaps slightly less clear, but may run ever so slightly faster because it allows Type::Tiny to play tricks with inlining code. (By which I basically mean concatenating various strings of Perl code and evaling them, so that it can end up with a single sub that does the entire check/coercion rather than needing to call different subs to do the checks and the coercions.)

In this case it's unlikely to make any perceivable difference to performance, but if you had a large arrayref of such numbers you wanted to coerce, you might notice.

ArrayRef[ (Maybe[NumRange[0,100]])->plus_coercions(Num, 'undef') ]

OTHER TIPS

Yes. Refer to the TypeConstraints documentation and how to coerce a value.

http://metacpan.org/pod/Moose::Util::TypeConstraints

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top