属性=> 'Maybe [SomeSubtype]'返回Attribute()不传递类型约束

时间:2017-05-23 22:57:02

标签: perl moose

我已经使用强制创建了子类型Birth_d,如下所示,我正在尝试将其与内置Maybe类型结合使用,每Moose::Manual::Types

我收到错误You cannot coerce an attribute (birth_d) unless its type (Maybe[Birth_d]) has a coercion。这是完整的测试代码:

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 );

isa => 'Maybe[Birth_d]'替换isa => 'Birth_d'有效,但不是必需的。我需要让birth_d可选,如果没有提供,应该是undef。

我应该补充一点,我尝试使用MooseX :: Types将这个Birth_d类型放在一个单独的地方,但是发现它使用了非常正统的裸字,所以我慢慢退缩了。如果有意义的话,我愿意重新考虑它。

2 个答案:

答案 0 :(得分:4)

驼鹿does not do any chaining of coercions,换句话说,你必须明确告诉它如何转换为Maybe[Birth_d]

您可以通过将现有强制重用到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;

答案 1 :(得分:3)

我会发现没有Maybe [Birth_d]类型更有用,但只是使用Birth_d类型声明属性,而不是" required"集。

这样,如果传入有效的String,它将被接受,无效的String将导致错误,并且不需要传递任何内容。

但是,您可以强制使用类型:

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',
);

我只是没有看到能够为生日传递undef的价值 - 这比设置它更好吗?

我还建议您在软件包末尾使用no Moose::Util::TypeConstraints;no Moose;,或者在开头使用namespace::autoclean;,并在结尾处使用__PACKAGE__->meta->make_immutable;。你的学生班。