简体   繁体   English

在 Moose 中,我如何需要多个属性之一?

[英]In Moose, how do I require one of multiple attributes?

I would like to be able to declare one of a set of mutually dependent attributes required.我希望能够声明所需的一组相互依赖的属性中的一个。

Let's assume a simple example of Number 'nr_two' being 'nr_one' + 1, and 'nr_one' being 'nr_two' -1, with one of either having to be passed in upon initialization.让我们假设一个简单的例子,数字“nr_two”是“nr_one”+1,“nr_one”是“nr_two”-1,其中一个必须在初始化时传入。

So far, I have seen this problem solved for example through BUILDARGS checks and a lazy builder on each:到目前为止,我已经看到这个问题通过BUILDARGS检查和一个惰性构建器解决了:

has 'nr_one' => (
    is => 'ro',
    isa => 'Num',
    lazy => 1,
    builder => '_build_nr_one',
);
sub _build_nr_one { shift->nr_two - 1; }

has 'nr_two' => (
    is => 'ro',
    isa => 'Num',
    lazy => 1,
    builder => '_build_nr_two',
);
sub _build_nr_two { shift->nr_one + 1; }

around 'BUILDARGS' => sub {
    my $orig = shift; 
    my $self = shift; 
    my $args = is_hashref($_[0])? $_[0] : { @_ }; 
    die "Either nr_one or nr_two is required!" unless defined $args{nr_one} || defined $args{nr_two};
    return $self->$orig($args);
};

Or, avoiding the around:或者,避开周围:

has 'nr_one' => (
    is => 'ro',
    isa => 'Num',
    predicate => 'has_nr_one',
    lazy => 1,
    builder => '_build_nr_one',
);
sub _build_nr_one { shift->nr_two - 1; }

has 'nr_two' => (
    is => 'ro',
    isa => 'Num',
    predicate => 'has_nr_two',
    lazy => 1,
    builder => '_build_nr_two',
);
sub _build_nr_two { shift->nr_one + 1; }

sub BUILD { 
    my $self = shift;
    die "Either nr_one or nr_two is required!" unless $self->has_nr_one || $self->has_nr_two;
}

However, I am looking for something that can be declared on the attributes, for example a grouping of some sort that can then be introspected and, for example, triggered in BUILD.但是,我正在寻找可以在属性上声明的东西,例如某种可以自省的分组,例如,在 BUILD 中触发。

Ideally, I'd like to ship this into a generic role or Meta class to make it available with some sort of nicer syntax, to avoid having to check for BUILD(ARGS) checks or rely on the pod to declare things accurately.理想情况下,我想将它发送到一个通用角色或 Meta class 以使其具有某种更好的语法,以避免必须检查 BUILD(ARGS) 检查或依赖 pod 准确地声明事物。

Is there cpan module that could help with this, or a pattern someone is aware of to achieve this?是否有 cpan 模块可以帮助解决这个问题,或者有人知道实现这一点的模式? Any hints / partial solutions are appreciated, if not:)任何提示/部分解决方案表示赞赏,如果不是:)

An example of what I would imagine would look something like this:我想象的一个例子看起来像这样:

has 'nr_one' => (
    is => 'ro',
    isa => 'Num',
    lazy => 1,
    builder => '_build_nr_one',
    required_grouping => 'NumberGroup',
);
sub _build_nr_one { shift->nr_two - 1; }

has 'nr_two' => (
    is => 'ro',
    isa => 'Num',
    lazy => 1,
    builder => '_build_nr_two',
    required_grouping => 'NumberGroup',

);
sub _build_nr_two { shift->nr_one + 1; }

# when initialized without any attributes, error thrown:
# "One of 'nr_one', 'nr_two' is required"
# or, probably easier: "NumberGroup required!"

I did not find a way to make a custom MooseX::Type or attribute trait automatically add a method modifier to BUILDARGS() that would validate the attributes.我没有找到一种方法来使自定义MooseX::Type属性特征自动将方法修饰符添加到BUILDARGS()以验证属性。 But it is simple to do that with a Moose::Role like this:但是使用这样的Moose::Role很简单:

#! /usr/bin/env perl
package NumberGroup;
use Moose::Role;
around 'BUILDARGS' => sub {
    my $orig = shift; 
    my $self = shift; 
    my $args = (ref $_[0]) eq "HASH" ? $_[0] : { @_ }; 
    die "Either nr_one or nr_two is required!" unless defined $args->{nr_one} || defined $args->{nr_two};
    return $self->$orig($args);
};


package Main;
use Moose;

with 'NumberGroup';

has 'nr_one' => (
    is       => 'ro',
    isa      => 'Num',
);

has 'nr_two' => (
    is       => 'ro',
    isa      => 'Num',
);

package main;
use strict;
use warnings;
Main->new();

Output : Output

Either nr_one or nr_two is required! at ./p.pl line 8.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM