在调用BUILDARGS时,我很难正确使用MooseX :: Declare。
我正在尝试创建一个对象作为文件的接口。 (具体来说,我想要一个二进制文件的接口,让我可以查看文件中的下一个字节,然后将它们关闭以进行进一步处理。)
我希望能够像这样创建其中一个对象
my $f = binary_file_buffer->new( $file_name );
然后像这样使用它
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 ] )
);
}
我的binary_file_buffer类定义/声明看起来像这样
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 );
}
}
(缓冲区加载和管理代码我没有在这里包含。它非常直接。)
问题是,我在method
声明中使用关键字BUILDARGS
。因此,MooseX :: Declare期望binary_file_buffer
对象作为BUILDARGS
的第一个参数。但BUILDARGS
获取传递给new的参数,因此第一个参数是 string a 'binary_file_buffer'
,即包的名称。因此,它在使用new创建对象时无法进行类型检查并死亡,就像我在第一个代码片段中所做的那样。 (至少那是我对正在发生的事情的理解。)
我得到的错误信息是:
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
我喜欢method
关键字为$ file_name提供的类型检查糖,但我不知道如何获取它,因为BUILDARGS
在技术上不是一种方法。
MooseX :: Declare是否有办法跳过$self
创建,或类似的东西?
我这样做是否适当的MooseX :: Declare方式?或者我错过了什么?
答案 0 :(得分:10)
我认为你想要method BUILDARGS (ClassName $class: Str $filename) { ... }
这样的东西,你明确地将调用者定义为ClassName $class
。
答案 1 :(得分:2)
我想你想要:
#!/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";
答案 2 :(得分:1)
这也是一种非常巧妙的方式(只是在我之前扩展答案):
use MooseX::MultiMethods;
multi method BUILDARGS (ClassName $class: Str $filename) {
#do whatever you want to do if only a strg is passed
}
这样,如果你不打电话,MooseX :: MultiMethods会注意这一点
FileHandle-> new($ file_name),
但是
FileHandle->new(
_filename => $file_name
);
(这是正常的语法),
它仍然可以使用!
另外,你可以(对文件名不太有用,但在其他情况下)
添加
multi method ( ClassName $class, Int $some_number ){}
这样,new现在可以处理hashrefs,整数和字符串......
哦可能性......;)