如何在构建期间设置ro属性?

时间:2017-02-04 19:05:15

标签: perl moose

我正在编写一个脚本来帮助我精通Moose。我有以下代码:

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

要解决此错误,我可以为rwbuilder属性设置属性dirs或使用files方法。前一种解决方案是不可取的,后一种解决方案需要重复代码(例如,目录需要打开两次),因此也是不可取的。

这个问题的最佳解决方案是什么?

2 个答案:

答案 0 :(得分: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中的任何东西。如果您的用户想要进入内部,他们会。

答案 1 :(得分:-2)

我找到了一个可能的解决方案,尽管它不赞成:

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