2011-04-28 5 views
3

ハッシュテーブルはPerlオブジェクトの典型的な初期化子です。これで、指定されたキーが定義された値になるかどうか、またはキーがまったく存在するかどうかがわからないという点で、入力が信頼できません。今度は、そのような信頼できない入力をMooseオブジェクトに供給したいのですが、欠けているキーは完全に大丈夫ですが、未定義の値を取り除きたいので、未定義の属性でいっぱいのオブジェクトにならないようにします。Mooseコンストラクタがundef引数を無視するようにします。

オブジェクトをインスタンス化して未定義の値をフィルタリングする際には、十分注意する必要があります。しかし、それが1つの場所にあるので、コンストラクタにそのフィルタをインストールしたいとしましょう。コンストラクタに未定義の値を無視させ、それらに遭遇すると死ぬことは望ましくありません。

アクセサメソッドの場合は、aroundを使用して、属性をundefに設定しないようにすることができます。しかし、method modifiersはコンストラクタのために呼び出されるのではなく、アクセサのためだけに呼び出されます。 c'torと同じ効果を得るために、つまりundef属性が受け入れられないようにするために、Mooseにも同様の機能がありますか?

属性がundefの場合、Moose Anyタイプはオブジェクトにハッシュキーを作成することに注意してください。 %$selfにはundefの値が含まれないようにしたいので、私は望んでいません。

ここで私がやったいくつかのテストです:

package Gurke; 
use Moose; 
use Data::Dumper; 

has color => is => 'rw', isa => 'Str', default => 'green'; 
has length => is => 'rw', isa => 'Num'; 
has appeal => is => 'rw', isa => 'Any'; 

around color => sub { 
    # print STDERR Dumper \@_; 
    my $orig = shift; 
    my $self = shift; 
    return $self->$orig unless @_; 
    return unless defined $_[0]; 
    return $self->$orig(@_); 
}; 

package main; 
use Test::More; 
use Test::Exception; 

my $gu = Gurke->new; 
isa_ok $gu, 'Gurke'; 
diag explain $gu; 
ok ! exists $gu->{length}, 'attribute not passed, so not set'; 
diag q(attempt to set color to undef - we don't want it to succeed); 
ok ! defined $gu->color(undef), 'returns undef'; 
is $gu->color, 'green', 'value unchanged'; 
diag q(passing undef in the constructor will make it die); 
dies_ok { Gurke->new(color => undef) } 
    'around does not work for the constructor!'; 
lives_ok { $gu = Gurke->new(appeal => undef) } 'anything goes'; 
diag explain $gu; 
diag q(... but creates the undef hash key, which is not what I want); 
done_testing; 
+0

[Moose :: Cookbook](http://search.cpan.org/perldoc/Moose::Cookbook)をお読みください。特に[Moose :: Cookbook :: Basics :: Recipe10](http://search.cpan.org/perldoc/Moose::Cookbook::Basics::Recipe10)。 –

答えて

13

これはまさにMooseX::UndefTolerantの機能です。クラスを不変にすると、生成されたコンストラクタにコードがインライン展開されるため、独自のBUILDARGSメソッドを作成するよりもはるかに高速になります。

+0

ああ私のオハイオ州私は、非常に多くのムースがあります:: WhatNotとMooseX :: WhatElseモジュール...そして彼らは私が欲しいものをまさにやります! :-)それはもっとぶらぶらして、おもちゃを使うだろうと思う。おかげでEther、これはおそらくあなたのBUILDARGSを書くことより優れているので、私はこれを最善の答えとして受け入れています。 – Lumi

+3

@マイケル::) ircがあなたのものなら、irc.perl.org #mooseで24/7に近い優れたサポートネットワークを見つけることができます。多くの場合、あなたが望むことをする拡張子がない場合、誰かがあなたのためにバックルをつけて書きます。ちょうどキックのために! :D – Ether

+0

ありがとう! IRCを実際に行ったことはありませんが、これは試してみる機会のように聞こえます。どんなクライアントに行くのですか? 'tin'のようなものは古典的な選択肢で、Cygwinで利用できます。また、Windows用の 'mIRC'を試してみてください。 – Lumi

5

はちょうどあなた自身のBUILDARGSサブルーチンを提供しています。

package Gurke; 

... 

around 'BUILDARGS' => sub{ 
    my($orig,$self,@params) = @_; 
    my $params; 
    if(@params == 1){ 
    ($params) = @params; 
    }else{ 
    $params = { @params }; 
    } 

    for my $key (keys %$params){ 
    delete $params->{$key} unless defined $params->{$key}; 
    } 

    $self->$orig($params); 
}; 
+0

素晴らしい、ありがとう、ブラッド!私の最初の本能は、 'keys'を' each'で置き換えることでしたが、反復中に 'delete'を呼び出すときには、そうしてはいけません。とても有難い! – Lumi

1

私はそれが多少重複努力であることを認識していますが、BUILDARGSでctorのをフックすることができます

around BUILDARGS => sub { 
    my $orig = shift; 
    my $class = shift; 
    my %params = ref $_[0] ? %{$_[0]} : @_; 

    return $class->$orig(
     map { $_ => $params{$_} } 
     grep { defined $params{$_} } 
     keys %params 
    ); 
}; 

編集:編集CTORに渡されたとしても、参照をサポートします。

+0

誰かが 'Class-> new({key => value})'を呼び出す(つまり、リストの代わりにハッシュリファレンスを渡す)場合、これは機能しません。 – cjm

+0

@cjm - ありがとう、私はそれが可能であることを知らなかった。 – bvr

0

この例題は、コンストラクタに渡されたundef属性を処理したいという欲求に触発されていますが、質問自体はundefだけをコンストラクタに渡すケースを意味します。解決する。例えば、Class->new(undef)

bvr's BUILDARGS answerが好きです。コンストラクタへの唯一の引数としてハッシュリファレンスの代わりにはundef値を渡す場合に対処するように拡張することができます。

around BUILDARGS => sub { 
    my $orig = shift; 
    my $class = shift; 
    my %params = defined $_[0] ? ref $_[0] ? %{$_[0]} : @_ :(); 

    return $class->$orig(
     map { $_ => $params{$_} } 
     grep { defined $params{$_} } 
     keys %params 
    ); 
}; 

MooseX ::はUndefTolerantはこのケースをサポートするためには表示されません。

関連する問題