Perl Moose - 检查变量是否是 Moose 数据类型

发布于 2024-10-20 14:06:32 字数 3034 浏览 6 评论 0原文

我正在将遗留应用程序转换为使用 Moose(和 Catalyst)并有以下问题。

如何确定用户输入的数据的 Moose 类型?

在下面的粗略示例中,我“提交”多个查询,并使用下面非常基本的“验证”方法根据预期的表单字段“id”、“name”和“email”验证数据。

use MooseX::Declare;
class CheckFields
{
    #has '_field' => ( is => 'rw', isa => 'Any' );

    # Fields on form and type to which they must match.
    method fields()
    {
        return [ { name => 'id',    type => 'Int' },
                 { name => 'name',  type => 'Str' },
                 { name => 'email', type => 'Email' }
               ];
    }

    # Dummy form posted requests.
    method queries()
    {
        return [ { 'id'    => 1,
                   'name'  => 'John Doe',
                   'email' => '[email protected]'
                 },
                 { 'id'    => 'John Doe',
                   'name'  => 1,
                   'email' => 'john.at.doe.net'
                 }
               ];
    }

    method validate_fields()
    {
        my $fields = $self->fields();

        # Loop through dummy form post requests
        foreach my $query ( @{ $self->queries } )
        {
            # Validate each field in posted form.
            foreach my $field ( @{ $fields } )
            {
                my $type = $field->{'type'};
                my $name = $field->{'name'};

                my $res = $self->validate->{ $type }( $query->{ $name} );
                print "$name is $res\n";
            }
            print "\n";
        }
    }

    # Very basic, slightly crude field validation.
    method validate()
    {
        return { 'Int'   => sub { my $val = shift; return $val =~ /^\d+$/ ? "ok" : "not ok" },
                 'Str'   => sub { my $val = shift; return $val =~ /^[a-zA-Z\s]+$/ ?"ok" : "not ok"  },
                 'Email' => sub { my $val = shift; return $val =~ /^(.+)\@(.+)$/ ?"ok" : "not ok"  }
               };
    }
}

要测试此代码,只需运行...

#!/usr/bin/perl
use Moose;
use CheckFields;

CheckFields->new()->validate_fields();

1;

是否可以执行类似的操作,将 isa 设置为“Any”...

has '_validate_field' => ( is => 'rw', isa => 'Any' );

然后测试特定类型,如下所示?

$self->validate_field(1);
print $self->validate_field->meta->isa('Int') ? 'Int found' : 'Int not found';

$self->validate_field('ABC');
print $self->validate_field->meta->isa('Int') ? 'Int found' : 'Int not found';

提前感谢您

编辑:@bvr - 感谢您花时间回复,我对 Moose 比较陌生,所以您使用 MooseX::Params::Validate 很可能是最终的解决方案不完全是我想要的。我的目的是能够报告错误的每个特定字段,而不是报告整个验证失败。为此,我想我可以定义一个默认的、对 Moose 友好的输入持有者,并将 isa 设置为“Any”。然后“eval”(或类似的)来查看数据是否符合特定类型(Int、Str 或我定义的某些自定义类型)。

我试图通过“$self->validate_field->meta->isa('Int')...”引用来达到 C/C++ 中联合的目的,其中变量可以可以是不同的类型 - 在这种情况下,我只是想测试数据是否符合某种数据类型。

I'm converting a legacy application to use Moose (and Catalyst) and have the following question.

How do I determine Moose Type of data input by a user?

In the following, crude, example I 'submit' multiple queries and validate the data against expected form fields 'id', 'name' and 'email' using the very basic 'validate' method below.

use MooseX::Declare;
class CheckFields
{
    #has '_field' => ( is => 'rw', isa => 'Any' );

    # Fields on form and type to which they must match.
    method fields()
    {
        return [ { name => 'id',    type => 'Int' },
                 { name => 'name',  type => 'Str' },
                 { name => 'email', type => 'Email' }
               ];
    }

    # Dummy form posted requests.
    method queries()
    {
        return [ { 'id'    => 1,
                   'name'  => 'John Doe',
                   'email' => '[email protected]'
                 },
                 { 'id'    => 'John Doe',
                   'name'  => 1,
                   'email' => 'john.at.doe.net'
                 }
               ];
    }

    method validate_fields()
    {
        my $fields = $self->fields();

        # Loop through dummy form post requests
        foreach my $query ( @{ $self->queries } )
        {
            # Validate each field in posted form.
            foreach my $field ( @{ $fields } )
            {
                my $type = $field->{'type'};
                my $name = $field->{'name'};

                my $res = $self->validate->{ $type }( $query->{ $name} );
                print "$name is $res\n";
            }
            print "\n";
        }
    }

    # Very basic, slightly crude field validation.
    method validate()
    {
        return { 'Int'   => sub { my $val = shift; return $val =~ /^\d+$/ ? "ok" : "not ok" },
                 'Str'   => sub { my $val = shift; return $val =~ /^[a-zA-Z\s]+$/ ?"ok" : "not ok"  },
                 'Email' => sub { my $val = shift; return $val =~ /^(.+)\@(.+)$/ ?"ok" : "not ok"  }
               };
    }
}

To test this code simply run...

#!/usr/bin/perl
use Moose;
use CheckFields;

CheckFields->new()->validate_fields();

1;

Is it possible to do something like this where you setup a variable with isa set to 'Any' ...

has '_validate_field' => ( is => 'rw', isa => 'Any' );

...then test for specific types as follows?

$self->validate_field(1);
print $self->validate_field->meta->isa('Int') ? 'Int found' : 'Int not found';

$self->validate_field('ABC');
print $self->validate_field->meta->isa('Int') ? 'Int found' : 'Int not found';

Thank you in advance

EDIT : @bvr - thank you for taking the time to reply, I'm relatively new to Moose so your use of MooseX::Params::Validate might well be the end solution though not quite what I'm looking for. My intention is to be able to report each specific field that is in error rather than reporting a validation failure as a whole. To that end I thought I could define a default, Moose friendly, input holder with isa set to 'Any'. Then 'eval' (or some such) to see if the data conformed to a particular type (Int, Str or some customised type defined by me).

What I was trying to get at with the "$self->validate_field->meta->isa('Int')..." reference was something along the lines of a union in C/C++ where a variable can be of different types - in this instance I'm just trying to test if the data conforms to a certain data type.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一身软味 2024-10-27 14:06:32

我不确定我是否完全遵循您问题的最后部分,但您最初的示例可以受益于使用 MooseX::Params::Validate

编辑:我编写了一些代码来评估我的建议。

use MooseX::Declare;
class CheckFields {

    use Moose::Util::TypeConstraints;
    use MooseX::Params::Validate;
    use Try::Tiny;
    use Data::Dump qw(pp);

    subtype 'Email' 
        => as 'Str' 
        => where {/^(.+)\@(.+)$/};

    method fields() {
        return [
            id    => {isa => 'Int'},
            name  => {isa => 'Str'},
            email => {isa => 'Email'},
        ];
    }

    method queries() {
        return [
            {   'id'    => 1,
                'name'  => 'John Doe',
                'email' => '[email protected]'
            },
            {   'id'    => 'John Doe',
                'name'  => 1,
                'email' => 'john.at.doe.net'
            }
        ];
    }

    method validate_fields() {
        my $fields = $self->fields();

        foreach my $query (@{$self->queries}) {
            try {
                my (%params) = validated_hash([%$query], @{$fields});
                warn pp($query) . " - OK\n";
            }
            catch {
                warn pp($query) . " - Failed\n";
            }
        }
    }
}

package main;

CheckFields->new()->validate_fields();

我能看到的其他方法是为数据创建一个 Moose 类(包括这种方式的验证)并检查是否可以在没有验证错误的情况下创建实例。像这样的事情:

use MooseX::Declare;
class Person {
    use Moose::Util::TypeConstraints;

    subtype 'Email'
        => as 'Str'
        => where {/^(.+)\@(.+)$/};

    has id    => (is => 'ro', isa => 'Int');
    has name  => (is => 'ro', isa => 'Str');
    has email => (is => 'ro', isa => 'Email');
}

package main;

use Try::Tiny;
use Data::Dump qw(pp);

my @tests = (
    { id => 1,          name => 'John Doe', email => '[email protected]'},
    { id => 'John Doe', name => 1,          email => 'john.at.doe.net'},
);

for my $query (@tests) {
    try {
        my $person = Person->new(%$query);
        warn pp($query) . " - OK\n";
    }
    catch {
        warn pp($query) . " - Failed\n";
    };
}

I am not sure I quite follow last part of your question, but your initial example could benefit from use of MooseX::Params::Validate.

Edit: I made some code to evaluate my suggestion.

use MooseX::Declare;
class CheckFields {

    use Moose::Util::TypeConstraints;
    use MooseX::Params::Validate;
    use Try::Tiny;
    use Data::Dump qw(pp);

    subtype 'Email' 
        => as 'Str' 
        => where {/^(.+)\@(.+)$/};

    method fields() {
        return [
            id    => {isa => 'Int'},
            name  => {isa => 'Str'},
            email => {isa => 'Email'},
        ];
    }

    method queries() {
        return [
            {   'id'    => 1,
                'name'  => 'John Doe',
                'email' => '[email protected]'
            },
            {   'id'    => 'John Doe',
                'name'  => 1,
                'email' => 'john.at.doe.net'
            }
        ];
    }

    method validate_fields() {
        my $fields = $self->fields();

        foreach my $query (@{$self->queries}) {
            try {
                my (%params) = validated_hash([%$query], @{$fields});
                warn pp($query) . " - OK\n";
            }
            catch {
                warn pp($query) . " - Failed\n";
            }
        }
    }
}

package main;

CheckFields->new()->validate_fields();

Other approach I can see is to make a Moose class for data (validation included this way) and check if instance can be created without validation error. Something like this:

use MooseX::Declare;
class Person {
    use Moose::Util::TypeConstraints;

    subtype 'Email'
        => as 'Str'
        => where {/^(.+)\@(.+)$/};

    has id    => (is => 'ro', isa => 'Int');
    has name  => (is => 'ro', isa => 'Str');
    has email => (is => 'ro', isa => 'Email');
}

package main;

use Try::Tiny;
use Data::Dump qw(pp);

my @tests = (
    { id => 1,          name => 'John Doe', email => '[email protected]'},
    { id => 'John Doe', name => 1,          email => 'john.at.doe.net'},
);

for my $query (@tests) {
    try {
        my $person = Person->new(%$query);
        warn pp($query) . " - OK\n";
    }
    catch {
        warn pp($query) . " - Failed\n";
    };
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文