2009-09-03 48 views
6

我有困難使用MooseX ::調用BUILDARGS時正確聲明。使用MooseX :: Declare創建BUILDARGS方法的正確方法是什麼?

我試圖創建一個對象作爲文件的接口。 (具體而言,我想一個二進制文件,讓我在文件在未來幾個字節偷看那麼的Chomp趕走作進一步處理的接口。)

我希望能夠創建這些對象的一個​​這樣的

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

(這裏沒有包含緩衝區加載和管理代碼。這是相當直接的)。

問題是,我在BUILDARGS聲明中使用關鍵字method。因此,MooseX :: Declare預計binary_file_buffer對象作爲BUILDARGS的第一個參數。但BUILDARGS獲取傳遞給新的參數,所以第一個參數是字符串 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方式嗎?或者我錯過了什麼?

回答

10

我想你想要的東西像method BUILDARGS (ClassName $class: Str $filename) { ... }其中你明確定義了調用者爲ClassName $class

+1

賓果!這正是我想要的。 我錯過了文檔中的2件事情,您的回覆說明了。 首先,我沒有在Moose :: Manual :: Types文檔中看到Str的ClassName子類型。我不期望內置的ClassName字符串子類型。 其次,我沒有看到MooseX :: Method :: Signatures文檔顯示如何命名方法的invocant並聲明它的類型。我沒有意識到MooseX :: Declare使用的方法簽名語法來自MooseX :: Method :: Signatures包。 到目前爲止,我愛MooseX :: Declare。我知道有一種駝鹿的方式來做我想做的事。我無法弄清楚如何。謝謝。 – meta4 2009-09-03 17:14:33

+0

使用ClassName而不是Object for method/around應該真的寫在MooseX :: Declare手冊的某處...也被這個咬傷了 – anydot 2011-04-12 18:06:10

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"; 
1

也這樣做(只是我之前回答的擴張)的一個非常簡潔的方式:

use MooseX::MultiMethods; 

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

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

} 

這樣,MooseX ::多方法將要小心,如果你不叫 FileHandle->新($ FILE_NAME),

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

(這是正常的語法),

它仍然能工作!

此外,您可以(這是不那麼有用的文件名,但在其他情況下)

添加

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

這樣一來,新的現在能處理hashrefs,整數和字符串...

哦的可能性...;)

相關問題