2010-12-02 3 views
10

He sido un defensor de la adopción de Moose (y MooseX :: Declare) en el trabajo durante varios meses. El estilo que fomenta realmente ayudará a la mantenibilidad de nuestra base de código, pero no sin algún costo inicial de aprendizaje de nueva sintaxis, y especialmente al aprender a analizar los errores de validación de tipo.Sucinta MooseX :: Declarar errores de validación de la firma del método

que he visto discusión en línea de este problema, y ​​pensé que había puesto una consulta a esta comunidad para:

a) soluciones conocidas

b) discusión de lo que los mensajes de error de validación debe ser similar

c) proponer una prueba de concepto que implementa algunas ideas

también voy a contactar con los autores, pero he visto alguna buena discusión en este foro también, así que pensé que había puesto algo público.

#!/usr/bin/perl 

use MooseX::Declare; 
class Foo { 

    has 'x' => (isa => 'Int', is => 'ro'); 

    method doit(Int $id, Str :$z, Str :$y) { 
     print "doit called with id = " . $id . "\n"; 
     print "z = " . $z . "\n"; 
     print "y = " . $y . "\n"; 
    } 

    method bar() { 
     $self->doit(); # 2, z => 'hello', y => 'there'); 
    } 
} 

my $foo = Foo->new(x => 4); 
$foo->bar(); 

Tenga en cuenta la falta de coincidencia en la llamada a Foo :: doit con la firma del método.

El mensaje de error que se produce es:

Validation failed for 'MooseX::Types::Structured::Tuple[MooseX::Types::Structured::Tuple[Object,Int],MooseX::Types::Structured::Dict[z,MooseX::Types::Structured::Optional[Str],y,MooseX::Types::Structured::Optional[Str]]]' failed with value [ [ Foo=HASH(0x2e02dd0) ], { } ], Internal Validation Error is: Validation failed for 'MooseX::Types::Structured::Tuple[Object,Int]' failed with value [ Foo{ x: 4 } ] at /usr/local/share/perl/5.10.0/MooseX/Method/Signatures/Meta/Method.pm line 441 
MooseX::Method::Signatures::Meta::Method::validate('MooseX::Method::Signatures::Meta::Method=HASH(0x2ed9dd0)', 'ARRAY(0x2eb8b28)') called at /usr/local/share/perl/5.10.0/MooseX/Method/Signatures/Meta/Method.pm line 145 
    Foo::doit('Foo=HASH(0x2e02dd0)') called at ./type_mismatch.pl line 15 
    Foo::bar('Foo=HASH(0x2e02dd0)') called at ./type_mismatch.pl line 20 

creo que la mayoría de acuerdo en que esto no es tan directa como podría ser. He implementado un corte en mi copia local de MooseX :: Método Método :: Firmas :: :: Meta que produce esta salida para el mismo programa:

Validation failed for 

    '[[Object,Int],Dict[z,Optional[Str],y,Optional[Str]]]' failed with value [ [ Foo=HASH(0x1c97d48) ], { } ] 

Internal Validation Error: 

    '[Object,Int]' failed with value [ Foo{ x: 4 } ] 

Caller: ./type_mismatch.pl line 15 (package Foo, subroutine Foo::doit) 

El código super-hacky que hace esto es

if (defined (my $msg = $self->type_constraint->validate($args, \$coerced))) { 
     if($msg =~ /MooseX::Types::Structured::/) { 
      $msg =~ s/MooseX::Types::Structured:://g; 
      $msg =~ s/,.Internal/\n\nInternal/; 
      $msg =~ s/failed.for./failed for\n\n /g; 
      $msg =~ s/Tuple//g; 
      $msg =~ s/ is: Validation failed for/:/; 
     } 
     my ($pkg, $filename, $lineno, $subroutine) = caller(1); 
     $msg .= "\n\nCaller: $filename line $lineno (package $pkg, subroutine $subroutine)\n"; 
     die $msg; 
    } 

[Nota: con unos pocos minutos más de rastrear el código, parece que MooseX :: :: Meta TypeConstraint :: :: estructurado de validación es un poco más cerca del código que debe ser cambiado. En cualquier caso, la pregunta sobre el mensaje de error ideales, y si alguien está trabajando activamente en o pensando en cambios similares se destaca]

que lleva a cabo 3 cosas:.

1) Menos detallado, más espacios en blanco (debatí incluyendo s/tupla //, pero la que mantiene con ella por ahora)

2) incluyendo llamando archivo/línea (con el uso frágil de la persona que llama (1))

3) morir en lugar de confesar - ya que como Veo que la principal ventaja de confess fue encontrar el punto de entrada del usuario en la verificación de tipo de todos modos, lo que podemos lograr en w menos detallado ays

Por supuesto que en realidad no quiero apoyar este parche. Mi pregunta es: ¿cuál es la mejor manera de equilibrar la integridad y la brevedad de estos mensajes de error, y hay planes actuales para poner algo así en su lugar?

Respuesta

10

Me alegra que te guste MooseX::Declare. Sin embargo, los errores de validación de la firma de método no son realmente de allí, sino de MooseX::Method::Signatures, que a su vez usa MooseX::Types::Structured para sus necesidades de validación. Cada error de validación que ve actualmente viene sin modificaciones desde MooseX::Types::Structured.

También voy a ignorar la parte pila-rastro del mensaje de error. Sucede que encontrarlos increíblemente útil, y lo mismo ocurre con el resto de los alces de Cabal. No voy a para eliminarlos de forma predeterminada.

Si desea una forma de apagarlos, alces necesita ser cambiado para lanzar una excepción objetos en lugar de cadenas de errores de validación de tipo de restricciones y, posiblemente, otras cosas. Esos siempre podrían capturar una traza inversa, pero la decisión en si mostrarla o no, o cómo exactamente formatearla cuando se muestra, podría hacerse en otro lugar, y el usuario podría modificar el comportamiento predeterminado - globalmente, localmente Léxico, lo que sea.

Lo que voy a tratar es la construcción de los mensajes reales de error de validación para firmas de métodos.

Como se señaló, MooseX::Types::Structured hace la validación real trabajo. Cuando algo falla al validar, es su trabajo presentar una excepción. Esta excepción actualmente resulta ser una cadena, por lo que no es tan útil cuando desea generar errores hermosos, por lo que debe cambiar, similar al problema con los restos de pila anteriores.

Una vez MooseX :: :: Tipos estructurado arroja objetos estructurado de excepciones, lo que podría parece algo

bless({ 
    type => Tuple[Tuple[Object,Int],Dict[z,Optional[Str],y,Optional[Str]]], 
    err => [ 
     0 => bless({ 
      type => Tuple[Object,Int], 
      err => [ 
       0 => undef, 
       1 => bless({ 
        type => Int, 
        err => bless({}, 'ValidationError::MissingValue'), 
       }, 'ValidationError'), 
      ], 
     }, 'ValidationError::Tuple'), 
     1 => undef, 
    ], 
}, 'ValidationError::Tuple') 

tendríamos suficiente información disponible para correlacionar realidad errores de validación interiores individuales con las piezas de la firma en MooseX::Method::Signatures. En el ejemplo anterior, y dado su firma (Int $id, Str :$z, Str :$y), sería bastante fácil saber que el interior Validation::MissingValue para el segundo elemento de la tupla para los parámetros posicionales se suponía que proporcione un valor para $id, pero no podía ' t.

Teniendo en cuenta que, será fácil de generar errores como

http://files.perldition.org/err1.png

o

http://files.perldition.org/err2.png

que es una especie de lo que voy a, en lugar de sólo dar formato a los mensajes horribles tenemos ahora más bien. Sin embargo, si uno quería hacer eso, se había siendo lo suficientemente fácil una vez que hemos estructurado excepciones de validación en lugar de cadenas simples.

Nada de esto es realmente difícil - sólo hay que hacer. Si alguien tiene ganas de ayudar con esto, ven a hablar con nosotros en #moose en irc.perl.org.

+0

Gracias, eso es realmente útil.Aunque ahora mi pregunta es: 1) ¿cuál es la forma de Moose-y de lanzar excepciones estructuradas como esa, y 2) si eso es demasiado problema sería más fácil factorizar la validación de tipo para no usar excepciones para denotar la falla de validación? Estaré encantado de ayudar con el proyecto, cualquiera que sea la solución ideal. ¿Cuánto trabajo crees que sería? Me gusta su formato de mensaje de error propuesto. Realmente ayudaría a un grupo como el mío a alcanzar la máxima velocidad con MooseX :: Declare. –

+0

@adamp: Un lugar donde se crean excepciones estructuradas de Moose está en MooseX :: Constructor :: AllErrors: esta sería otra fuente de ideas sobre cómo resolver el problema de "Las excepciones de los alces deben ser objetos" de una manera más universal . – Ether

+0

@ether: Gracias por el consejo. Echaré un vistazo a MooseX :: Constructor :: AllErrors para tener una idea de cómo deben crearse y arrojarse estos errores de validación. –

1

Method::Signatures::Modifiers es un paquete que espera solucionar algunos de los problemas de MooseX::Method::Signatures. Simplemente use sobrecargarlo.

use MooseX::Declare; 
use Method::Signatures::Modifiers; 

class Foo 
{ 
    method bar (Int $thing) { 
     # this method is declared with Method::Signatures instead of MooseX::Method::Signatures 
    } 
} 
Cuestiones relacionadas