suppressしたrow objの存在しないkeyにアクセスして、Data::WeightedRoundRobin の初期値が使われて...orz

たった今、かなしい!となったので勢いに任せて書きます.

普段、Data::WeightedRoundRobin のSugarを次のような感じで exportして使っています.

use Data::WeightedRoundRobin;

sub list2dwr (&@) {## no critic
    my $code = shift;
    return Data::WeightedRoundRobin->new([ map { $code->($_) } @_ ])
}

my $dwr = list2dwr {
    +{
       key    => $_,
       value  => $_ * $_,
       weight => $_,
    }
} qw/1 2 3 4/;

普段、Teng のsuppress_object_creation も、データが多くなるってとき、 使っています.

my @rows = do {
    my $iter = model('DB::Hoge')->search(+{ user_id => $args->{user_id} });
    $iter->suppress_object_creation(1);
    $iter->all;
};

で、はまったコードはこれ.

my @rows = do {
    my $iter = model('DB::Hoge')->search(+{ user_id => $args->{user_id} });
    $iter->suppress_object_creation(1);
    $iter->all;
};

my $dwr = list2dwr {
    +{
       key    => $_->{id},
       value  => $_,
       weight => $_->{weihgt},
    }
} @rows;

分かりにくいと思うので、拡大!! コレ!!!!!

weight => $_->{weihgt}, # not weight!!!

順としては

  • $_->{weihgt} が undefined
  • Data::WeightedRoundRobin の、DEFAULT_WEIGHT 100が適用される
  • orz

テストコードで気づくと思いつつ、意地悪なテストじゃなかったら、すり抜けるなーと

普段、次のような恩恵を自然と預かっているんだなと改め思う - $_->weight に対するアクセスが普段メソッド通しているので、typoに気づく - hashへのアクセスもバリデータを通しているので、気づく - readonly にしていればとか、、、

だから、どうしよう… と思ったが少し閃いた

どうせ、ラップして使っているなら、default値は使わないぜ作戦

sub list2dwr (&@) {## no critic
    my $code = shift;
    return Data::WeightedRoundRobin->new([ map { $code->($_) } @_ ], { default_weight => sub { die } } )
}

Data::WeightedRoundRobin で、default_weight がコードリファレンスだったら実行してもらう必要があるけど、、

あとは、suppress_object_creation でreadonlyにする作戦?!

comments powered by Disqus