File Coverage

blib/lib/Sub/Rate.pm
Criterion Covered Total %
statement 45 47 95.7
branch 8 10 80.0
condition n/a
subroutine 9 9 100.0
pod 3 3 100.0
total 65 69 94.2


line stmt bran cond sub pod time code
1             package Sub::Rate;
2 4     4   2740 use strict;
  4         9  
  4         117  
3 4     4   18 use warnings;
  4         7  
  4         90  
4 4     4   1582 use Moo;
  4         34430  
  4         19  
5 4     4   4675 use Carp;
  4         11  
  4         746  
6              
7             our $VERSION = '0.06';
8              
9             has max_rate => (
10             is => 'rw',
11             default => 100,
12             );
13              
14             has rand_func => (
15             is => 'rw',
16             default => sub {
17             return sub { rand($_[0]) };
18             },
19             );
20              
21             has sort => (
22             is => 'rw',
23             default => 0,
24             );
25              
26             has _func => (
27             is => 'rw',
28             default => sub { [] },
29             );
30              
31             has _default_func => (
32             is => 'rw',
33             );
34              
35 4     4   29 no Moo;
  4         10  
  4         18  
36              
37             sub add {
38 11     11 1 1107 my ($self, $rate, $func) = @_;
39              
40 11 100       36 if ($rate eq 'default') {
41 1         5 $self->_default_func($func);
42             }
43             else {
44 10         15 my $total_rate = 0;
45 10         16 $total_rate += $_->[0] for @{ $self->_func };
  10         46  
46              
47 10 100       44 if ($total_rate + $rate > $self->max_rate) {
48 1         160 croak sprintf 'Exceed max_rate, current:%s max:%s',
49             $total_rate + $rate, $self->max_rate;
50             }
51              
52 9         16 push @{ $self->_func }, [$rate, $func];
  9         37  
53             }
54             }
55              
56             sub generate {
57 3     3 1 16 my ($self) = @_;
58              
59 3         5 my @sorted_funcs = @{ $self->_func };
  3         13  
60 3 50       23 @sorted_funcs = CORE::sort { $a->[0] <=> $b->[0] } @sorted_funcs if $self->sort;
  0         0  
61              
62 3         27 my $rand = $self->rand_func;
63 3         10 my $max_rate = $self->max_rate;
64 3         10 my $default_func = $self->_default_func;
65              
66             sub {
67 200100     200100   766622 my @args = @_;
68              
69 200100         253215 my $index = $rand->($max_rate);
70 200100         241678 my $cursor = 0;
71              
72 200100         249349 for my $f (@sorted_funcs) {
73 356871         433568 $cursor += $f->[0];
74              
75 356871 100       577629 if ($index <= $cursor) {
76 130231         201209 return $f->[1]->(@args);
77             }
78             }
79              
80 69869 50       98925 if ($default_func) {
81 69869         98453 return $default_func->(@args);
82             }
83             else {
84 0         0 return;
85             }
86 3         35 };
87             }
88              
89             sub clear {
90 2     2 1 2624 my ($self) = @_;
91 2         19 $self->_func([]);
92 2         59 $self->_default_func(undef);
93             }
94              
95             __PACKAGE__->meta->make_immutable;
96              
97             __END__