2017-02-04 12 views
0

私はMooseに習熟するためのスクリプトを書いています。私は、次のコードビットを持っている:次のエラーでビルド中にro属性を設定するには?

package Dir; 
use Moose; 
use Modern::Perl; 
use File; 

has 'dirs' =>    (is => 'ro', isa => 'HashRef[Dir]'); 
has 'files' =>   (is => 'ro', isa => 'HashRef[File]'); 
has 'dir_class' =>  (is => 'ro', isa => 'ClassName', default => 'Dir'); 
has 'file_class' =>  (is => 'ro', isa => 'ClassName', default => 'File'); 

sub BUILD { 
    my $self = shift; 
    my $path = $self->path; 
    my $name = $self->name; 
    my (%dirs, %files); 

    # populate dirs attribute with LaborData::Data::Dir objects 
    opendir my $dh, $path or die "Can't opendir '$path': $!"; 

    # Get files and dirs and separate them out 
    my @dirs_and_files = grep { ! m{^\.$|^\.\.$} } readdir $dh; 
    closedir $dh or die "Can't closedir '$path': $!"; 
    my @dir_names   = grep { -d "$path/$_" } grep { !m{^\.} } @dirs_and_files; 
    my @file_names  = grep { -f "$path/$_" } grep { !m{^\.} } @dirs_and_files; 

    # Create objects 
    map { $dirs{$_}   = $self->dir_class->new (path => $path . '/' . $_) } @dir_names; 
    map { $files{$_}  = $self->file_class->new (path => $path . '/' . $_) } @file_names; 

    # Set attributes 
    $self->dirs   (\%dirs); 
    $self->files  (\%files); 
} 

コード結果:died: Moose::Exception::CannotAssignValueToReadOnlyAccessor (Cannot assign a value to a read-only accessor at reader Dir::dirs

このエラーを回避するために、私が作ることができるのいずれかの属性rwまたはdirsためbuilderメソッドを使用します属性はfilesです。前者の解決法は望ましくなく、後者の解決法はコードの重複を必要とする(例えば、ディレクトリを2回開く必要がある)ので、また望ましくない。

この問題の最適な解決策は何ですか?

+1

「StevensPerlTools」が何をしているのだろうか。 :) – simbabque

答えて

2

あなたの読み取り専用属性にa writerを割り当てて、あなたのBUILDから内部的に使用することができます。それが内部であることを示すために_という名前を付けてください。

package Foo; 
use Moose; 

has bar => (is => 'ro', writer => '_set_bar'); 

sub BUILD { 
    my $self = shift; 

    $self->_set_bar('foobar'); 
} 

package main; 
Foo->new; 

これは例外をスローしません。

これは本質的にはrwと同じですが、現在はライターと同じアクセサーではありません。 _はそれが内部であることを示しているので、rwを使用するよりもあまり望ましくありません。とにかくPerlでは何も保護できないことを覚えておいてください。あなたのユーザーが内部にアクセスしたい場合、彼らはそうします。

+0

OK、ありがとうございます。これはこれを達成する最善の方法のようです。 – StevieD

+0

@simbabque:すべての 'ro'属性*は' writer'を与えられなければなりません。そうでないと永遠に初期化されません。また、私は今夜は格好いいと思われるので、上記のあなたの冗談を説明してください。 – Borodin

+0

@Borodin以前は、編集の前に 'use StevesPerlTools;'行がありました。 – melpomene

-2

それは眉をひそめていますけれども、私は、一つの可能​​な解決策を見つけた:

# Set attributes 
    $self->{dirs} = \%dirs; 
    $self->{files} = \%files; 
+4

しないでください。ムースを学びたいなら、内部を混乱させないでください。 – simbabque

関連する問題