使用 MooseX::Declare 创建 BUILDARGS 方法的正确方法是什么?

发布于 2024-08-03 21:21:14 字数 3075 浏览 7 评论 0原文

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

(这里没有包含缓冲区加载和管理代码。它相当简单。)

问题是,我使用关键字 methodBUILDARGS 声明中。因此,MooseX::Declare 需要一个 binary_file_buffer object 作为 BUILDARGS 的第一个参数。但是 BUILDARGS 获取传递给 new 的参数,因此第一个参数是 '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 方式执行此操作?或者我错过了什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

与风相奔跑 2024-08-10 21:21:14

我认为您想要类似 method BUILDARGS (ClassName $class: Str $filename) { ... } 的东西,其中您将调用者显式定义为 ClassName $class

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

仙气飘飘 2024-08-10 21:21:14

我想你想要:

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

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";
狼亦尘 2024-08-10 21:21:14

这也是一种非常巧妙的方法(只是我面前答案的扩展):

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 现在可以处理哈希引用、整数和字符串......

哦可能性......;)

also a really neat way of doing it (just an expansion of the answer before me):

use MooseX::MultiMethods;

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

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

}

that way, MooseX::MultiMethods will take care that if you do NOT call
FileHandle->new( $file_name ),

but

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

(which is the normal syntax),

it would still work!

Also, you could ( which is not so useful for filenames but in other cases )

add a

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

that way, new could now handle hashrefs, integers and strings...

oh the possibilities... ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文