【问题标题】:Perl/Moose object initialization with coercion into ArrayRef强制转换为 ArrayRef 的 Perl/Moose 对象初始化
【发布时间】:2013-11-20 21:43:27
【问题描述】:

需要制作一个接受一个或多个paths的模块,并将它们强制转换为Class::Path 的数组。在 CPAN 中存在一个模块 MooseX::Types::Path::Class。从它的来源我发现模块定义的子类型DirFile

我的示例模块:

package Web::Finder;
use namespace::sweep;
use Modern::Perl;

use Moose;
use MooseX::Types::Path::Class qw(Dir);  #??? - is this correct?
use Method::Signatures::Simple;
use Path::Class;

#should accept one or more directories as Str or as Path::Class::Dir
has 'volumes' => (
    is => 'ro',         
    isa => 'ArrayRef[Path::Class::Dir]', #Can I use here a simple 'ArrayRef[Dir]' ?
    required => 1,
    coerce => 1,
);

has 'fs' => (
    is => 'ro',
    isa => 'ArrayRef[File::System]',
    lazy => 1,
    builder => '_create_volumes',
);

#is the next correct?
method _create_volumes {
    push $self->fs, File::System->new('Real', root => $_->stringify) for ($self->volumes);
}

还有我的剧本

#!/usr/bin/env perl
use Modern::Perl;
use Web::Finder;

my $f = Web::Finder->new(volumes => .... ???

我应该在上面的模块中改变什么来接受下一次初始化?

my $f = My::Module->new(volumes => "/some/path");

my $f = My::Module->new(volumes => [qw(/some/path1 /another/path2)] );

或类似的东西 - 所以:一条或多条路径...

根据我理解的错误消息,我比我做错了什么... ;)

You cannot coerce an attribute (volumes) unless its type (ArrayRef[Path::Class::Dir]) has a coercion at Web/Finder.pm line 14.
    require Web/Finder.pm called at x line 2
    main::BEGIN() called at Web/Finder.pm line 0
    eval {...} called at Web/Finder.pm line 0
Attribute (volumes) does not pass the type constraint because: Validation failed for 'ArrayRef[Path::Class::Dir]' with value ARRAY(0x7f812b0040b8) at constructor Web::Finder::new (defined at Web/Finder.pm line 33) line 42.
    Web::Finder::new("Web::Finder", "volumes", ARRAY(0x7f812b0040b8)) called at x line 6

问题的下一部分是如何为每个volume 创建一个File::System 实例。 builder 方法正确吗?

会很高兴得到任何帮助和/或 cmets。

【问题讨论】:

    标签: perl moose


    【解决方案1】:
    1. 要从一个或多个路径强制转换,您需要声明这些类型的强制转换。 MooseX::Types::Path::Class 确实定义了强制,但不是您需要的强制(它们只会强制到单个 Path::Class 对象,而不是它们的数组)。

      subtype 'ArrayOfDirs', as 'ArrayRef[Path::Class::Dir]';
      
      coerce 'ArrayOfDirs',
          # for one path
          from 'Str',           via { [ Path::Class::Dir->new($_) ] },
          # for multiple paths
          from 'ArrayRef[Str]', via { [ map { Path::Class::Dir->new($_) } @$_ ] }; 
      
      has 'volumes' => (
          is => 'ro',
          isa => 'ArrayOfDirs',
          required => 1,
          coerce => 1,
      );
      
    2. builder 方法应返回 File::System 对象的 ArrayRef。

      sub _create_volumes {
          my ($self) = @_;
          return [
              map { File::System->new('Real', root => $_->stringify) }
                  $self->volumes
          ];
      }
      
    3. 您可以将卷声明为'ArrayRef[Dir]' 吗?不,不是那种形式。 MooseX::Types::Path::Class 中的Dir 定义为MooseX::Types 类型,这意味着它需要用作裸字,而不是字符串。

      use MooseX::Types::Moose qw( ArrayRef );
      use MooseX::Types::Path::Class qw( Dir );
      
      has 'volumes' => (
          is => 'ro',
          isa => ArrayRef[Dir],
          required => 1,
          coerce => 1,
      );
      

    【讨论】:

    • 太棒了!非常感谢你。我还在学习 Moose,老实说,这并不容易……
    猜你喜欢
    • 1970-01-01
    • 2014-05-01
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多