2009-09-03 7 views
6

J'ai du mal à utiliser MooseX :: Declare correctement lorsque j'appelle BUILDARGS. J'essaie de créer un objet en tant qu'interface pour un fichier. (Spécifiquement, je veux une interface à un fichier binaire qui me laisse jeter un coup d'oeil aux quelques octets suivants dans le fichier puis les chompez pour un traitement ultérieur.)Quelle est la bonne façon de créer une méthode BUILDARGS en utilisant MooseX :: Declare?

Je veux être capable de créer un de ces objets

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

puis l'utiliser comme ceci

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 ]) 
    ); 
} 

Mon de binary_file_buffer définition de classe/déclaration se présente comme suit

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); 
    } 
} 

(Il y a un chargement de tampon et un code de gestion que je n'ai pas inclus ici. C'est assez simple.)

Le problème est que j'utilise le mot-clé method dans la déclaration BUILDARGS. Par conséquent, MooseX :: Declare attend un objetbinary_file_buffercomme premier argument à BUILDARGS. Mais BUILDARGS obtient les arguments passés à nouveau, de sorte que le premier argument est la chaîne un 'binary_file_buffer', le nom du package. Par conséquent, il échoue à la vérification de type et meurt lors de la création d'un objet en utilisant new, comme je l'ai fait dans le premier extrait de code. (Au moins, c'est ma compréhension de ce qui se passe.)

Le message d'erreur que je reçois est:

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 

J'aime le type de vérification sucre les fournitures de mots clés method pour file_name $, mais je ne sais pas comment l'obtenir puisque BUILDARGS n'est pas techniquement une méthode.

MooseX :: Declare peut-il ignorer la création $self, ou quelque chose comme ça? Est-ce que je fais cela la bonne façon MooseX :: Declare? Ou est-ce que je manque quelque chose?

Répondre

10

Je pense que vous voulez quelque chose comme method BUILDARGS (ClassName $class: Str $filename) { ... } dans lequel vous définissez explicitement l'invocant comme ClassName $class.

+1

Bingo! Cela fait exactement ce que je veux. J'ai raté 2 choses dans les docs, votre réponse a été clarifiée. D'abord, je n'ai pas vu le sous-type ClassName de Str dans Moose :: Manual :: Types docs. Je ne m'attendais pas à un sous-type de chaîne ClassName. Ensuite, je n'ai pas vu les docs MooseX :: Method :: Signatures montrer comment nommer l'invocant d'une méthode et déclarer son type. Je n'ai pas réalisé que la syntaxe de signature de méthode utilisée par MooseX :: Declare provient du paquetage MooseX :: Method :: Signatures. Jusqu'ici, j'adore MooseX :: Declare. Je savais qu'il y avait une façon Moose de faire ce que je voulais. Je ne pouvais pas comprendre comment. Merci. – meta4

+0

L'utilisation de ClassName au lieu de Object pour method/around devrait vraiment être écrite quelque part dans le manuel de MooseX :: Declare ... a été mordu par ça aussi – anydot

2

Je pense que vous voulez:

#!/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

aussi un moyen vraiment bien de le faire (juste une extension de la réponse avant moi):

use MooseX::MultiMethods; 

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

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

} 

cette façon, MooseX :: Multiméthodes sera prendre soin que si vous ne l'appelez pas FileHandle-> nouveau (nom_fichier $),

mais

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

(qui est la syntaxe normale),

il fonctionne encore!

De plus, vous pourriez (ce qui est si utile pour les noms de fichiers, mais dans d'autres cas)

ajouter un

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

cette façon, nouvelle pourrait désormais gérer hashrefs, entiers et les chaînes ...

oh les possibilités ...;)

Questions connexes