Perl Moose - проверить, является ли переменная типом данных Moose - PullRequest
5 голосов
/ 06 марта 2011

Я конвертирую устаревшее приложение, чтобы использовать Moose (и Catalyst), и у меня следующий вопрос.

Как определить тип данных Moose, вводимых пользователем?

В следующем грубом примере я «отправляю» несколько запросов и проверяю данные по ожидаемым полям формы «id», «name» и «email», используя очень простой метод «validate» ниже.

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' => 'john@doe.net'
                 },
                 { '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';

Заранее спасибо

EDIT : @bvr - спасибо, что нашли время ответить, я относительно новичок в Moose, так что использование MooseX :: Params :: Validate вполне может быть конечным решением, хотя и не совсем что я ищу Мое намерение состоит в том, чтобы иметь возможность сообщать о каждом конкретном поле, в котором произошла ошибка, а не сообщать об ошибке проверки в целом. С этой целью я подумал, что смогу определить по умолчанию, Moose friendly, держатель ввода с isa , установленным на ' Any '. Затем 'eval' (или некоторые другие), чтобы увидеть, соответствуют ли данные определенному типу (Int, Str или некоторому настроенному мной типу, определенному мной).

То, что я пытался получить с помощью ссылки "$ self-> validate_field-> meta-> isa ('Int') ...", было чем-то вроде объединения в C / C ++, где переменная может быть разных типов - в данном случае я просто пытаюсь проверить, соответствуют ли данные определенному типу данных.

1 Ответ

2 голосов
/ 06 марта 2011

Я не уверен, что полностью следую последней части вашего вопроса, но ваш первоначальный пример может выиграть от использования 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' => 'john@doe.net'
            },
            {   '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 => 'john@doe.net'},
    { 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";
    };
}
...