What’s the proper way to create a BUILDARGS method using MooseX::Declare?

moose, perl

Solution

I think you want something like `method BUILDARGS (ClassName $class: Str $filename) { ... }` in which you explicitly define the invocant as `ClassName $class`.

Problem

I'm having difficulty using MooseX::Declare properly when calling BUILDARGS. I'm trying to create an object as an interface for a file. (Specifically, I want an interface to a binary file that lets me peek at the next few bytes in the file then chomp them off for further processing.) I want to be able to create one of these objects like this ``` my $f = binary_file_buffer->new( $file_name ); ``` and then use it like this ``` 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 ] ) ); } ``` My of binary_file_buffer class definition/declaration looks like this ``` 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 ); } } ``` (There is buffer loading and managing code that I didn't include here. It is fairly straight forward.) The problem is, I use the keyword `method` in the `BUILDARGS` declaration. So, MooseX::Declare expects a `binary_file_buffer` object as the first argument to `BUILDARGS`. But `BUILDARGS` gets the arguments passed to new, so the first argument is the string a `'binary_file_buffer'`, the name of the package. As a result it fails the type checking and dies when creating an object using new, like I did in the first code snippet. (At least that's my understanding of what is happening.) The error message I get is: ``` 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 ``` I like the type checking sugar the `method` keyword supplies for $file_name, but I don't know how to get it since `BUILDARGS` isn't technically a method. Does MooseX::Declare have a way to skip the `$self` creation, or something like that? Am I doing this the proper MooseX::Declare way? Or am I missing something?

Original source