File Coverage

blib/lib/Nanoid.pm
Criterion Covered Total %
statement 51 51 100.0
branch 9 10 90.0
condition 6 7 85.7
subroutine 11 11 100.0
pod 0 1 0.0
total 77 80 96.2


line stmt bran cond sub pod time code
1             package Nanoid;
2 2     2   230882 use 5.010;
  2         10  
3 2     2   10 use strict;
  2         3  
  2         37  
4 2     2   21 use warnings;
  2         3  
  2         95  
5              
6             our $VERSION = "0.04";
7              
8 2     2   11 use strict;
  2         3  
  2         46  
9 2     2   9 use warnings;
  2         3  
  2         63  
10              
11 2     2   11 use POSIX qw(ceil);
  2         10  
  2         15  
12 2     2   3326 use Carp qw(croak);
  2         4  
  2         154  
13 2     2   1222 use Bytes::Random::Secure qw(random_bytes);
  2         20444  
  2         112  
14              
15 2     2   14 use constant DEFAULT_SIZE => 21;
  2         4  
  2         104  
16 2         558 use constant DEFAULT_ALPHABETS =>
17 2     2   12 '_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  2         2  
18              
19             sub generate {
20 100006     100006 0 897911 my (%opts) = @_;
21              
22 100006   100     270528 my $size = $opts{size} // DEFAULT_SIZE;
23 100006   100     216013 my $alphabet = $opts{alphabet} // DEFAULT_ALPHABETS;
24              
25 100006         123988 my $alphabet_size = length $alphabet;
26              
27 100006 100       156228 if ( $size <= 0 ) {
28 1         98 croak 'size must be greater than zero';
29             }
30              
31 100005 100 66     252816 if ( $alphabet_size == 0 || $alphabet_size > 255 ) {
32 1         259 croak 'alphabet must not empty and contain no more than 255 chars';
33             }
34              
35 100004         724881 my @alphabet_array = split( '', $alphabet );
36 100004         211812 my $mask = ( 2 << ( log( $alphabet_size - 1 ) / log(2) ) ) - 1;
37              
38 100004         220612 my $step = ceil( 1.6 * $mask * $size / $alphabet_size );
39 100004         128268 my $id = '';
40              
41 100004         117560 while (1) {
42 100004         176594 my $bytes = [ unpack( 'C*', random_bytes($step) ) ];
43              
44 100004         8982292 for my $idx ( 0 .. $step ) {
45 2100053         2139600 my $byte;
46              
47 2100053 50       3182250 if ( defined $bytes->[$idx] ) {
48 2100053         2364578 $byte = $bytes->[$idx] & $mask;
49              
50 2100053 100       2950254 if ( defined $alphabet_array[$byte] ) {
51 2100052         2516482 $id .= $alphabet_array[$byte];
52             }
53             }
54              
55 2100053 100       3208181 if ( length $id == $size ) {
56 100004         644766 return $id;
57             }
58             }
59             }
60              
61             }
62              
63             1;
64             __END__