File Coverage

blib/lib/Sub/Frequency.pm
Criterion Covered Total %
statement 32 33 96.9
branch 9 12 75.0
condition 4 4 100.0
subroutine 10 10 100.0
pod 1 1 100.0
total 56 60 93.3


line stmt bran cond sub pod time code
1             package Sub::Frequency;
2              
3 5     5   142504 use strict;
  5         13  
  5         183  
4 5     5   23 use warnings;
  5         9  
  5         142  
5              
6 5     5   25 use Scalar::Util 'looks_like_number';
  5         11  
  5         615  
7 5     5   26 use Carp 'croak';
  5         8  
  5         312  
8              
9 5     5   4467 use parent 'Exporter';
  5         2080  
  5         30  
10              
11             our @EXPORT = qw(
12             always normally usually often sometimes maybe
13             rarely seldom never with_probability
14             );
15              
16             our @EXPORT_OK = @EXPORT;
17              
18             our $VERSION = '0.05';
19              
20             my %probabilities = (
21             'Sub::Frequency::Always' => 1.00,
22             'Sub::Frequency::Normally' => 0.75,
23             'Sub::Frequency::Sometimes' => 0.50,
24             'Sub::Frequency::Rarely' => 0.25,
25             'Sub::Frequency::Never' => 0.00,
26             );
27              
28             foreach my $name (keys %probabilities) {
29             (my $subname = lc($name)) =~ s/.*:://g;
30 5     5   725 no strict 'refs';
  5         10  
  5         2151  
31             *$subname = sub (&;@) {
32 400     400   2626 my ( $code, @rest ) = @_;
33 400 100       582 if (wantarray) {
34 100         311 return ( bless( $code, $name ), @rest );
35             }
36             else {
37 300         430 _exec( $code, $name, @rest );
38             }
39             }
40             }
41              
42             sub with_probability ($;&) {
43 200     200 1 2282 my ( $probability, $code ) = @_;
44              
45 200 50       416 $probability = _coerce($probability)
46             unless looks_like_number($probability);
47              
48 200 100       504 $code->() if rand() <= $probability;
49             }
50              
51             *often = \&normally;
52             *usually = \&normally;
53             *maybe = \&sometimes;
54             *seldom = \&rarely;
55              
56             sub _exec {
57 300     300   375 my ( $code, $name, @rest ) = @_;
58              
59 300 100 100     817 $code->() and return if rand() < $probabilities{$name};
60              
61 201         427 foreach $code (@rest) {
62 100 50 100     324 $code->() and last if rand() < $probabilities{ ref($code) };
63             }
64             }
65              
66             sub _coerce {
67 8     8   4460 my $thing = shift;
68              
69             # matches N%, .N% and N.N%
70 8 50       44 if ( $thing =~ m/^\s*(\d+|\d*\.\d+)\s*%\s*$/ ) {
71 8         51 return $1 / 100;
72             }
73             else {
74 0           croak "'$thing' does not look like a number or a percentage.";
75             }
76             }
77              
78             42;
79             __END__