2009-09-03 14 views
6

Tengo dificultades para usar MooseX :: Declare correctamente cuando llamo a BUILDARGS.¿Cuál es la forma correcta de crear un método BUILDARGS utilizando MooseX :: Declare?

Estoy intentando crear un objeto como una interfaz para un archivo. (Específicamente, quiero una interfaz para un archivo binario que me permita echar un vistazo a los siguientes bytes en el archivo y luego cortarlos para su posterior procesamiento.)

Quiero ser capaz de crear uno de estos objetos como este

my $f = binary_file_buffer->new($file_name); 

y luego usarlo como esto

while(my $block_id = $f->peek($id_offset, $id_length)) { 
    $block_id = unpack_block_id($block_id); 
    $munge_block{ $block_id }->(
     $f->pop($block_size[ $block_id ]) 
    ); 
} 

Mi binary_file_buffer de definición de clase/declaración se parece a esto

use MooseX::Declare; 
class binary_file_buffer { 
    use FileHandle; 
    use Carp; 

    has _file  => (is => 'ro', isa => 'FileHandle'); 
    has _file_name => (is => 'ro', isa => 'Str'); 
    has _buff  => (is => 'rw', isa => 'Str', default => ''); 

    method BUILDARGS (Str $file_name) { 
     my $file = FileHandle->new($file_name); 
     carp "unable to open $file_name : $!" unless defined $file; 
     $file->binmode; 
     return (
     _file_name => $file_name, 
     _file  => $file, 
    ); 
    } 

    # get the next n bytes from the buffer. 
    method pop (Int $len) { 
     # ... Make sure there is data in _buff 
     return substr($self->{_buff}, 0, $len, ''); 
    } 

    # Look around inside the buffer without changing the location for pop 
    method peek (Int $offset, Int $len) { 
     # ... Make sure there is data in _buff 
     return substr($self->{_buff}, $offset, $len); 
    } 
} 

(No es tampón de carga y el código de gestión que no he incluido aquí. Es bastante sencillo.)

El problema es que utilizo la palabra clave method en la declaración BUILDARGS. Así, MooseX :: Declare espera un objetobinary_file_buffercomo primer argumento a BUILDARGS. Pero BUILDARGS obtiene los argumentos que se pasan a la nueva, por lo que el primer argumento es la cadena un 'binary_file_buffer', el nombre del paquete. Como resultado, falla el tipo de comprobación y se agota al crear un objeto utilizando new, como hice en el primer fragmento de código. (Al menos esa es mi comprensión de lo que está sucediendo.)

El mensaje de error que consigo es:

Validation failed for 'MooseX::Types::Structured::Tuple[MooseX::Types::Structured::Tuple[Object,Str,Bool],MooseX::Types::Structured::Dict[]]' failed with value [ [ "binary_file_buffer", "drap_iono_t1.log", 0 ], { } ], Internal Validation Error is: Validation failed for 'MooseX::Types::Structured::Tuple[Object,Str,Bool]' failed with value [ "binary_file_buffer", "drap_iono_t1.log", 0 ] at C:/bin/perl/site/lib/MooseX/Method/Signatures/Meta/Method.pm line 445 
MooseX::Method::Signatures::Meta::Method::validate('MooseX::Method::Signatures::Meta::Method=HASH(0x2a623b4)', 'ARRAY(0x2a62764)') called at C:/bin/perl/site/lib/MooseX/Method/Signatures/Meta/Method.pm line 145 
binary_file_buffer::BUILDARGS('binary_file_buffer', 'drap_iono_t1.log') called at generated method (unknown origin) line 5 
binary_file_buffer::new('binary_file_buffer', 'drap_iono_t1.log') called at logshred.pl line 13 

me gusta la comprobación de tipos de azúcar las method suministros de palabras clave por $ nombre_archivo, pero no sé cómo obtenerlo desde BUILDARGS no es técnicamente un método.

¿El MooseX :: Declarar tener una forma de omitir la creación $self, o algo por el estilo?

estoy haciendo esto el MooseX adecuada :: Declarar manera? ¿O me estoy perdiendo algo?

Respuesta

10

Creo que desea algo como method BUILDARGS (ClassName $class: Str $filename) { ... } en el que defina explícitamente el invocante como ClassName $class.

+1

Bingo! Eso hace exactamente lo que quiero. Me perdí 2 cosas en los documentos que tu respuesta aclaró. En primer lugar, no vi el subtipo ClassName de Str en Moose :: Manual :: Types docs. No esperaba un subtipo de cadena ClassName incorporado. En segundo lugar, no vi que los documentos MooseX :: Method :: Signatures muestren cómo nombrar el invocador de un método y declarar su tipo. No me di cuenta de que la sintaxis de la firma del método que usa MooseX :: Declare es del paquete MooseX :: Method :: Signatures. Hasta ahora, amo MooseX :: Declare. Sabía que había una manera de Moose para hacer lo que quería. Simplemente no pude entender cómo. Gracias. – meta4

+0

Usar ClassName en lugar de Object para method/around debería escribirse en algún lugar del manual de MooseX :: Declare ... también fue mordido por esto – anydot

2

Creo que desee:

#!/use/bin/perl 

use strict; 
use warnings; 

use MooseX::Declare; 
class BinaryFile::Buffer { 
    use FileHandle; 
    use Carp; 

    has file  => (is => 'ro', isa => 'FileHandle'); 
    has file_name => (is => 'ro', isa => 'Str'); 
    has _buff  => (
     is  => 'rw', 
     isa  => 'Str', 
     default => '', 
     init_arg => undef 
    ); 

    sub BUILDARGS { 
     my ($class, $file_name) = @_; 
     my $file = FileHandle->new($file_name) or do { 
      carp "unable to open ", $file_name, " : $!"; 
      return; 
     }; 
     $file->binmode; 
     return $class->SUPER::BUILDARGS(
       file_name => $file_name, 
       file  => $file 
     ); 
    } 

    # get the next n bytes from the buffer. 
    method pop(Int $len) { 
     # ... Make sure there is data in _buff 
     return substr($self->buff, 0, $len, ''); 
    } 

    # Look around inside the buffer without changing the location for pop 
    method peek(Int $offset, Int $len) { 
     # ... Make sure there is data in _buff 
     return substr($self->buff, $offset, $len); 
    } 
} 

my $f = BinaryFile::Buffer->new($0); 

print $f->file_name, "\n"; 
1

también una manera muy ordenada de hacerlo (sólo una expansión de la respuesta antes que yo):

use MooseX::MultiMethods; 

multi method BUILDARGS (ClassName $class: Str $filename) { 

#do whatever you want to do if only a strg is passed 

} 

de esa manera, MooseX :: métodos múltiples se tener cuidado de que si usted no llama FileHandle-> nueva ($ nombre_archivo),

pero

FileHandle->new(
_filename => $file_name 
); 

(que es la sintaxis normal),

no por ello deja trabajar!

También, usted podría (que no es tan útil para los nombres de archivo, pero en otros casos)

añadir un

multi method (ClassName $class, Int $some_number){} 

de esa manera, nuevo ahora podía manejar hashrefs, enteros y cadenas ...

oh las posibilidades ...;)

Cuestiones relacionadas