Is attribute => 'Maybe [SomeSubtype]' returns attribute () does not skip type constraint

I created a Birth_d

coerced subtype as shown below and I am trying to use it in conjunction with a built-in type Maybe

, behind Moose :: Manual :: Types .

I am getting an error You cannot coerce an attribute (birth_d) unless its type (Maybe[Birth_d]) has a coercion

. Here's the complete test code:

package Student;
use Moose;
use Moose::Util::TypeConstraints;

use DateTime::Format::MySQL;

class_type 'Birth_d', { class => 'DateTime' };

coerce 'Birth_d',
  from 'Str',
  via { DateTime::Format::MySQL->parse_date( $_ ) };

has 'name' => (
  isa => 'Str',
  is => 'ro',
);

has 'birth_d' => (
  isa => 'Maybe[Birth_d]',   # This works:    isa => 'Birth_d'
  coerce => 1,
  is => 'ro',
);


package main;

use Test::More;

my $student = Student->new(
  name => 'Johnnie Appleseed',
  birth_d => '2015-01-01'
  );

is ( $student->birth_d->ymd(), '2015-01-01' );

my $student2 = Student->new(
  name => 'Foo Bar',
  birth_d => undef
  );

is( $student2->birth_d, undef );

      

Replacing isa => 'Maybe[Birth_d]'

with isa => 'Birth_d'

does works, but it's not what you need. I need to make the birth_d parameter optional, and if not specified, it should be undef.

I must add, I tried to use MooseX :: Types to remove this Birth_d type in a separate location, but found that his cavalry use of simple words was a bit unorthodox, so I slowly backed off. I am open to revising it if it makes sense to do so.

+3


source to share


2 answers


It would be more useful for me not to have the Maybe [Birth_d] type, but just declare the attribute with the Birth_d type and not a "required" set.

Thus, if a valid string is passed it will be accepted, an invalid string will result in an error, and nothing just needs to be passed.

However, you can coerce into a possible type:



subtype 'MaybeBirth_d',
    as maybe_type(class_type('DateTime'));

coerce 'MaybeBirth_d',
    from 'Str',
    via { DateTime::Format::MySQL->parse_date( $_ ) };

has 'birth_d' => (
    isa => 'MaybeBirth_d',
    coerce => 1,
    is => 'ro',
);

      

I just don't see the value of being able to pass in undef for the date of birth - how better than not setting it?

I would also suggest using no Moose::Util::TypeConstraints;

both no Moose;

at the end of your package or namespace::autoclean;

at the beginning as well as __PACKAGE__->meta->make_immutable;

at the end of your Student class.

+3


source


Moose does not enforce chaining , in other words, you must explicitly tell how to convert to Maybe[Birth_d]

.

You can do this by reusing the existing coercion before Birth_d

:



package Student;
use Moose;
use Moose::Util::TypeConstraints;

use DateTime::Format::MySQL;

# save the Moose::Meta::TypeConstraint object
# you can also get it with find_type_constraint('Birth_d')
my $birth_d = class_type 'Birth_d', { class => 'DateTime' };

coerce 'Birth_d',
  from 'Str',
   via { DateTime::Format::MySQL->parse_date( $_ ) };

subtype 'MaybeBirth_d',
     as 'Maybe[Birth_d]';

coerce 'Maybe[Birth_d]',
  from 'Str|Undef',
   via { $birth_d->coerce($_) };

has 'name' => (
  isa => 'Str',
  is => 'ro',
);

has 'birth_d' => (
  isa => 'Maybe[Birth_d]',
  coerce => 1,
  is => 'ro',
  predicate => 'has_birth_d', # as per your comment
);


package main;

use Test::More;

my $student = Student->new(
  name => 'Johnnie Appleseed',
  birth_d => '2015-01-01'
);

is ( $student->birth_d->ymd(), '2015-01-01' );

my $student2 = Student->new(
  name => 'Foo Bar',
  birth_d => undef
);

is( $student2->birth_d, undef );

ok( $student2->has_birth_d );

done_testing;

      

+4


source







All Articles