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!!!



順としては

  1. $_->{weihgt} が undefined
  2. Data::WeightedRoundRobin の、DEFAULT_WEIGHT 100が適用される
  3. 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にする作戦?!