2012-01-26 10 views
5

Usamos clases Moose que serializan iteradores en varios formatos de salida. Se describe el iterador como un atributo:Usando bended CodeRefs con restricciones de tipo Moose

has iterator => (
    is => 'ro', 
    isa => 'CodeRef', 
    required => 1, 
); 

Esto ha funcionado bien hasta ahora, pero últimamente hemos estado utilizando para preparar Iterator::Simple iteradores para el consumo posterior. Esto significa que podemos escribir esto:

has iterator => (
    is => 'ro', 
    isa => 'CodeRef|Iterator::Simple::Iterator', 
    required => 1, 
); 

Y permitamos que nuestros serializadores acepten la clase de iterador correctamente. Sin embargo, eso parece ser una solución incompleta.

¿Hay alguna manera en Moose para especificar la restricción de que el atributo debe ser invocable? Sospecho que puede ser posible con Moose::Util::TypeConstraints y usando overload::Overloaded en &{} para verificar, pero me gustaría saber si alguien ha creado un módulo para hacerlo o si existe una forma estándar de Moose para probar esto.

Respuesta

4

CodeRef solo permite referencias de código no descargables. Afortunadamente, es fácil hacer tus propios tipos.

Defina Callable como se muestra a continuación, luego úsela en lugar de CodeRef. Permite lo siguiente:

  • Referencias de códigos no válidos.
  • Referencias de códigos benditos.
  • Objetos que pretenden ser referencias de código (es decir, aquellos que sobrecargan &{}).

use Moose::Util::TypeConstraints; 
use overload  qw(); 
use Scalar::Util qw(); 

subtype 'Callable' 
    => as 'Ref' 
    => where { 
      Scalar::Util::reftype($_) eq 'CODE' 
      || 
      Scalar::Util::blessed($_) && overload::Method($_, "&{}") 
     } 

    # Written such that parent's inline_as needs not be prepended. 
    => inline_as {'(
      (Scalar::Util::reftype('.$_[1].') // "") eq 'CODE' 
      || 
      Scalar::Util::blessed('.$_[1].') && overload::Method('.$_[1].', "&{}") 
     )'}; 

no Moose::Util::TypeConstraints; 
Cuestiones relacionadas