2011-04-28 9 views
5

Moose types son geniales, pero a veces debe ser más específico. Todos ustedes conocen estas reglas de tipo de datos: ese parámetro solo puede ser 'A', 'B' o 'C', o solo un símbolo de moneda, o debe ajustarse a alguna expresión regular.Aplicar comprobación específica (más allá de los tipos de Moose) al atributo de Moose

Eche un vistazo al siguiente ejemplo que tiene dos atributos restringidos, uno debe ser 'm' o 'f', el otro debe ser una fecha ISO válida. ¿Cuál es la mejor manera en Moose para especificar estas restricciones? Pensaría en la cláusula SQL CHECK, pero AFAICS no hay check palabra clave en Moose. Entonces usé trigger, pero suena mal. Alguien tiene una mejor respuesta?

package Person; 
use Moose; 

has gender   => is => 'rw', isa => 'Str', trigger => 
    sub { confess 'either m or f' if $_[1] !~ m/^m|f$/ }; 
has name   => is => 'rw', isa => 'Str'; 
has dateOfBirth  => is => 'rw', isa => 'Str', trigger => 
    sub { confess 'not an ISO date' if $_[1] !~ m/^\d\d\d\d-\d\d-\d\d$/ }; 

no Moose; 
__PACKAGE__->meta->make_immutable; 

package main; 
use Test::More; 
use Test::Exception; 

dies_ok { Person->new(gender => 42) } 'gender must be m or f'; 
dies_ok { Person->new(dateOfBirth => 42) } 'must be an ISO date'; 

done_testing; 

Esto es lo que terminé usando:

package Blabla::Customer; 
use Moose::Util::TypeConstraints; 
use Moose; 

subtype ISODate => as 'Str' => where { /^\d\d\d\d-\d\d-\d\d$/ }; 

has id    => is => 'rw', isa => 'Str'; 
has gender   => is => 'rw', isa => enum ['m', 'f']; 
has firstname  => is => 'rw', isa => 'Str'; 
has dateOfBirth  => is => 'rw', isa => 'ISODate'; 

no Moose; 
__PACKAGE__->meta->make_immutable; 

Esta es la versión 1.19 alces, en caso de que importa. Recibí la siguiente advertencia para la erróneasubtype as => 'Str', where => { ... } sintaxis que introduje erróneamente: Calling subtype() with a simple list of parameters is deprecated. Así que tuve que cambiarlo un poco según el fino manual.

+1

** Respuesta: ** utilice sus propios tipos. –

Respuesta

6

Simplemente defina su propio subtipo y úselo.

package Person; 

use Moose::Util::TypeConstraints; 

use namespace::clean; 
use Moose; 

has gender => (
    is => 'rw', 
    isa => subtype(
    as 'Str', 
    where { /^[mf]$/ } 
), 
); 
has name => (
    is => 'rw', 
    isa => 'Str' 
); 
has dateOfBirth => (
    is => 'rw', 
    isa => subtype(
    as 'Str', 
    where { /^\d\d\d\d-\d\d-\d\d$/ } 
), 
); 

no Moose; 
__PACKAGE__->meta->make_immutable; 
1; 
package main; 
use Test::More; 
use Test::Exception; 

dies_ok { Person->new(gender => 42) } 'gender must be m or f'; 
dies_ok { Person->new(dateOfBirth => 42) } 'must be an ISO date'; 

done_testing; 

O usted podría utilizar el módulo MooseX::Types.

package Person::TypeConstraints; 

use MooseX::Types::Moose qw'Str'; 
use MooseX::Types -declare => [qw' 
    Gender ISODate 
']; 

subtype Gender, (
    as Str, 
    where { /^[mf]$/ }, 
); 

subtype ISODate, (
    as Str, 
    where { /^\d\d\d\d-\d\d-\d\d$/ } 
); 
1; 
package Person: 

use MooseX::Types::Moose qw'Str'; 
use Person::TypeConstraints qw'Gender ISODate'; 

use namespace::clean; 
use Moose; 

has gender => (
    is => 'rw', 
    isa => Gender, 
); 
has name => (
    is => 'rw', 
    isa => Str, 
); 
has dateOfBirth => (
    is => 'rw', 
    isa => ISODate, 
); 

no Moose; 
__PACKAGE__->meta->make_immutable; 
1; 
+2

Tengo que decir que confiar en el tipo 'Str' cuando Moose tiene un Enum TypeConstraint me resulta confuso. ¿Qué está mal con 'tiene género => (isa => enum ([qw | M m F f |]), es => 'ro'); '? – perigrin

+0

Terminé usando 'Moose :: Util :: TypeConstraints', que tiene la ventaja de que ya está instalado en el sistema de destino (que no controlo). Estoy seguro de que las otras sugerencias también son interesantes. Verifique mi publicación inicial donde voy a publicar una actualización ya que la sintaxis para llamar 'subtipo' difiere un poco de la presentada en su ejemplo. También hay 'enum' que encontré útil. ¡Gracias una tonelada! – Lumi

+0

Tengo que hacer una corrección. La sintaxis de Brad para 'subtipo 'estaba bien. Derramé los beans escribiendo 'subtipo as =>' Str ', donde => {...} ', que es incorrecto o desaprobado. Es un poco complicado que este se escriba de forma diferente a los otros modificadores de atributos. – Lumi

3

Añadiendo su propio tipo como Brad dijo:

use Moose::Util::TypeConstraints; 

my $gender_constraint = subtype as 'Str', where { $_ =~ /^[FfMm]$/ }; 
has gender => (is => 'rw', isa => $gender_constraint); 
+0

Esa es una forma de hacerlo, pero realmente solo tiene sentido si va a usarlo más de una vez, y solo en un archivo.Recomendaría usar [MooseX :: Types] (http://search.cpan.org/perldoc/MooseX::Types) si planea usar las mismas restricciones en más de un archivo. –

+0

Gracias. Aunque Brad no parece estar de acuerdo al 100%, creo que está bien almacenar y reutilizar el valor de retorno de 'subtipo', aunque podría limitarse a ese único alcance. Tal vez eso es lo que quieres? – Lumi

+0

@ Michael-Ludwig Sí, a menudo tengo cosas como $ abs_int y tales que se usan en varios lugares en una clase, así que creo que funciona bien para eso. Brad tiene razón en que MooseX :: Types es increíble si está utilizando las mismas restricciones en varios archivos, y la subtipificación en línea es buena para una única restricción. – SymKat

0

Usted podría tratar de usar MooseX-Types-Parameterizable para poner en práctica los tipos que tienen parámetros para los casos que presentan (no probados, que acabamos de esbozar):

package YourTypes; 
use MooseX::Types -declare => [qw(OneOfStr MatchingStr)]; 
use MooseX::Types::Moose qw(Str ArrayRef RegexpRef); 

subtype OneOfStr, 
    as Parameterizable[ Str, ArrayRef[ Str ] ], 
    where { 
     my ($str, $allowed) = @_; 
     return scalar grep { $_ eq $str } @$allowed; 
    }; 

subtype MatchingStr, 
    as Parameterizable[ Str, RegexpRef ], 
    where { 
     my ($str, $rx) = @_; 
     return scalar $str =~ $rx; 
    }; 

1; 

y lo usarías así:

use YourTypes qw(OneOfStr MatchingStr); 

has gender => (is => 'ro', isa => OneOfStr[ [qw(f m)] ]); 
has dob => (is => 'ro', isa => MatchingStr[ qr/^$yourregex$/ ]); 
+0

Gracias, voy a echar un vistazo. Mañana :-) – Lumi

Cuestiones relacionadas