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?
I think you want something like method BUILDARGS (ClassName $class: Str $filename) { ... }
in which you explicitly define the invocant as ClassName $class
.
I think you want:
#!/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";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With