是否可以使属性配置依赖于 Moo 中的另一个属性?
Is it possible to make an attribute configuration dependent on another attribute in Moo?
我已经阅读了各种教程和 Moo 文档,但我找不到任何描述我想做什么的内容。
我想做的是类似下面的事情:
has 'status' => (
is => 'ro',
isa => Enum[qw(pending waiting completed)],
);
has 'someother' => (
is => is_status() eq 'waiting' ? 'ro' : 'rw',
required => is_status() eq 'completed' ? 1 : 0,
isa => Str,
lazy => 1,
);
如果我与这个想法相去甚远,我将如何根据另一个属性的值来制作属性 'ro' 或 'rw' 以及是否需要?
注意,枚举来自 Type::Tiny。
问问自己为什么要这样做。你正在处理对象。这些是应用了一组逻辑的数据。 class 中描述了该逻辑,对象是应用了 class 逻辑的数据实例。
如果有一个属性(即数据)可以应用两种不同的逻辑,它仍然是相同的class吗?毕竟,属性是否可变是一个非常明确的规则。
所以你真的有两个不同的 classes。一种是 someother
属性 是只读的,另一种是可更改的。
在 Moo(和 Moose)中,有多种构建方法。
- 实施 Foo::Static 和 Foo::Dynamic(或可更改或其他),其中两者都是 Foo 的子class,并且只有一个 属性 更改
- 实现 Foo 并实现一个子class
- 实现 Foo 和一个改变
someother
行为的角色,并在构造函数中应用它。 Moo::Role inherits that from Role::Tiny.
这是使用角色的方法示例。
package Foo;
use Moo;
use Role::Tiny ();
has 'status' => ( is => 'ro', );
has 'someother' => (
is => 'ro',
lazy => 1,
);
sub BUILD {
my ( $self) = @_;
Role::Tiny->apply_roles_to_object($self, 'Foo::Role::Someother::Dynamic')
if $self->status eq 'foo';
}
package Foo::Role::Someother::Dynamic;
use Moo::Role;
has '+someother' => ( is => 'rw', required => 1 );
package main;
use strict;
use warnings;
use Data::Printer;
# ...
首先我们将创建一个具有动态 someother
.
的对象
my $foo = Foo->new( status => 'foo', someother => 'foo' );
p $foo;
$foo->someother('asdf');
print $foo->someother;
__END__
Foo__WITH__Foo::Role::Someother::Dynamic {
Parents Role::Tiny::_COMPOSABLE::Foo::Role::Someother::Dynamic, Foo
Linear @ISA Foo__WITH__Foo::Role::Someother::Dynamic, Role::Tiny::_COMPOSABLE::Foo::Role::Someother::Dynamic, Role::Tiny::_COMPOSABLE::Foo::Role::Someother::Dynamic::_BASE, Foo, Moo::Object
public methods (0)
private methods (0)
internals: {
someother "foo",
status "foo"
}
}
asdf
如您所见,这行得通。现在让我们做一个静态的。
my $bar = Foo->new( status => 'bar', someother => 'bar' );
p $bar;
$bar->someother('asdf');
__END__
Foo {
Parents Moo::Object
public methods (4) : BUILD, new, someother, status
private methods (0)
internals: {
someother "bar",
status "bar"
}
}
Usage: Foo::someother(self) at /home/julien/code/scratch.pl line 327.
糟糕。一个警告。不像 Moose 中那样是一个很好的 'read-only' 例外,但我想这已经是最好的了。
但是,这对 required
属性没有帮助。你可以创建一个没有 someother
的 Foo->new( status => 'foo' )
,它仍然可以正常运行。
所以您可能想要满足于子class 方法或使用角色并构建一个 factory class.
我已经阅读了各种教程和 Moo 文档,但我找不到任何描述我想做什么的内容。
我想做的是类似下面的事情:
has 'status' => (
is => 'ro',
isa => Enum[qw(pending waiting completed)],
);
has 'someother' => (
is => is_status() eq 'waiting' ? 'ro' : 'rw',
required => is_status() eq 'completed' ? 1 : 0,
isa => Str,
lazy => 1,
);
如果我与这个想法相去甚远,我将如何根据另一个属性的值来制作属性 'ro' 或 'rw' 以及是否需要?
注意,枚举来自 Type::Tiny。
问问自己为什么要这样做。你正在处理对象。这些是应用了一组逻辑的数据。 class 中描述了该逻辑,对象是应用了 class 逻辑的数据实例。
如果有一个属性(即数据)可以应用两种不同的逻辑,它仍然是相同的class吗?毕竟,属性是否可变是一个非常明确的规则。
所以你真的有两个不同的 classes。一种是 someother
属性 是只读的,另一种是可更改的。
在 Moo(和 Moose)中,有多种构建方法。
- 实施 Foo::Static 和 Foo::Dynamic(或可更改或其他),其中两者都是 Foo 的子class,并且只有一个 属性 更改
- 实现 Foo 并实现一个子class
- 实现 Foo 和一个改变
someother
行为的角色,并在构造函数中应用它。 Moo::Role inherits that from Role::Tiny.
这是使用角色的方法示例。
package Foo;
use Moo;
use Role::Tiny ();
has 'status' => ( is => 'ro', );
has 'someother' => (
is => 'ro',
lazy => 1,
);
sub BUILD {
my ( $self) = @_;
Role::Tiny->apply_roles_to_object($self, 'Foo::Role::Someother::Dynamic')
if $self->status eq 'foo';
}
package Foo::Role::Someother::Dynamic;
use Moo::Role;
has '+someother' => ( is => 'rw', required => 1 );
package main;
use strict;
use warnings;
use Data::Printer;
# ...
首先我们将创建一个具有动态 someother
.
my $foo = Foo->new( status => 'foo', someother => 'foo' );
p $foo;
$foo->someother('asdf');
print $foo->someother;
__END__
Foo__WITH__Foo::Role::Someother::Dynamic {
Parents Role::Tiny::_COMPOSABLE::Foo::Role::Someother::Dynamic, Foo
Linear @ISA Foo__WITH__Foo::Role::Someother::Dynamic, Role::Tiny::_COMPOSABLE::Foo::Role::Someother::Dynamic, Role::Tiny::_COMPOSABLE::Foo::Role::Someother::Dynamic::_BASE, Foo, Moo::Object
public methods (0)
private methods (0)
internals: {
someother "foo",
status "foo"
}
}
asdf
如您所见,这行得通。现在让我们做一个静态的。
my $bar = Foo->new( status => 'bar', someother => 'bar' );
p $bar;
$bar->someother('asdf');
__END__
Foo {
Parents Moo::Object
public methods (4) : BUILD, new, someother, status
private methods (0)
internals: {
someother "bar",
status "bar"
}
}
Usage: Foo::someother(self) at /home/julien/code/scratch.pl line 327.
糟糕。一个警告。不像 Moose 中那样是一个很好的 'read-only' 例外,但我想这已经是最好的了。
但是,这对 required
属性没有帮助。你可以创建一个没有 someother
的 Foo->new( status => 'foo' )
,它仍然可以正常运行。
所以您可能想要满足于子class 方法或使用角色并构建一个 factory class.