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.
source to share
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.
source to share
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;
source to share