Moose:在构造对象

时间:2018-04-01 10:06:58

标签: perl moose

我想在调用其BUILD方法后将对象的属性更改为只读。我怎么能这样做?

(上下文:我的程序加载了这个对象,我希望在创建之后用YAML创建它,使用MooseX::YAML,然后在BUILD方法中更改其属性,以解决限制YAML描述here。更具体地说,我的YAML代码声明了一个目录和一堆文件,但是在YAML中似乎无法表达所有这些文件必须在该目录中。我可以,当然,将这个目录名称添加到所有这些文件名中,使它们成为绝对名称,但这意味着1)当我改变主意关于目录的位置时,我必须更改这些文件的所有条目,而不是只更改目录名称,以及2)在创建对象之前从程序内部更改目录名称将是痛苦的,并且容易出错。)

(后来添加:)最小的工作示例。

yaml1:

# invalid YAML, unfortunately:
dir: &dir /here
file1: *dir/foo
file2: *dir/bar
# ... and a lot more

yaml2:

# works, but requires repeating '/here/':
dir: /here
file1: /here/foo
file2: /here/bar
# ...

yaml3:

# works, but requires making changes to attribute values:
dir: /here
file1: foo
file2: bar
# ...

program.perl:

use strict;
use warnings;
use lib '.';
use MooseX::YAML qw (LoadFile);
use Try::Tiny;

foreach (1..3) {
  my $datafile = "yaml$_";
  print STDERR "Loading $datafile...\n";
  try {
    LoadFile ("yaml$_");
  } catch {
    print STDERR "$_";
  };
}

在目录中创建所有这些文件并运行" perl program.perl"从那里,我得到以下输出:

Loading yaml1...
YAML::XS::Load Error: The problem:

    did not find expected alphabetic or numeric character

was found at document: 1, line: 2, column: 12
while scanning an alias at line: 2, column: 8
Loading yaml2...
Loading yaml3...

文件' mypkg.pm'显示使用yaml3时我必须对属性所做的更改。

mypkg.pm:

package mypkg;
use Moose;
use File::Spec;

has 'dir' => (isa => 'Str', is => 'ro');
# have to allow modifying these values in BUILD
#                                              (!!)
has [qw (file1 file2)] => (isa => 'Str', is => 'rw');

sub BUILD {
  my ($self) = @_;
  $self->file1 (File::Spec->catfile ($self->dir, $self->file1));
  $self->file2 (File::Spec->catfile ($self->dir, $self->file2));
  # ... etc.
  # everything done, I would like all further changes to the attribute 
  # values to be impossible from now on
}

__PACKAGE__->meta->make_immutable;

1 个答案:

答案 0 :(得分:4)

这是一种可以在BUILD() sub:

中写入只读属性的方法
package mypkg;
use Moose;
use File::Spec;

has [qw (file1 file2)] => (isa => 'Str', is => 'ro');
has dir => (isa => 'Str', is => 'ro');

sub BUILD {
    my ($self) = @_;
    # Note that we use $self->{file1} instead of $self->file1 in order to 
    # fool Moose and write to its read-only attributes
    $self->{file1} = File::Spec->catfile($self->dir, $self->file1);
    $self->{file2}  = File::Spec->catfile($self->dir, $self->file2);
}

另见Writing to read-only attributes inside a Perl Moose class