2013-11-20 5 views
1

Нужно создать модуль, который принимает один или несколько paths и принуждает их к массиву Class::Path. В CPAN существует модуль MooseX::Types::Path::Class. Из его источника я обнаружил, что модуль определил подтипы Dir и File.Инициализация объекта Perl/Moose с принуждением в ArrayRef

Мой пример модуля:

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 i nstance. Правильно ли используется метод builder?

Будем рады любой помощи и/или комментариям.

ответ

2
  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 Ожидается возвращение ссылку на массив из файла :: Системные объекты.

    sub _create_volumes { 
        my ($self) = @_; 
        return [ 
         map { File::System->new('Real', root => $_->stringify) } 
          $self->volumes 
        ]; 
    } 
    
  3. Вы можете объявить тома как 'ArrayRef[Dir]'? Нет, не в такой форме. Dir в MooseX :: Types :: Path :: Class определяется как тип 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, 
    ); 
    
+0

Отлично! Большое спасибо. Я все еще учусь Мусу, и, честно говоря, это непросто ... – novacik

 Смежные вопросы

  • Нет связанных вопросов^_^