File Coverage

blib/lib/Nanoid.pm
Criterion Covered Total %
statement 50 50 100.0
branch 7 8 87.5
condition 6 7 85.7
subroutine 11 11 100.0
pod 0 1 0.0
total 74 77 96.1


line stmt bran cond sub pod time code
1             package Nanoid;
2 2     2   228212 use 5.010;
  2         14  
3 2     2   10 use strict;
  2         4  
  2         37  
4 2     2   9 use warnings;
  2         4  
  2         90  
5              
6             our $VERSION = "0.03";
7              
8 2     2   11 use strict;
  2         3  
  2         51  
9 2     2   10 use warnings;
  2         3  
  2         80  
10              
11 2     2   12 use POSIX qw(ceil);
  2         4  
  2         21  
12 2     2   3362 use Carp qw(croak);
  2         6  
  2         103  
13 2     2   1154 use Bytes::Random::Secure qw(random_bytes);
  2         20037  
  2         118  
14              
15 2     2   14 use constant DEFAULT_SIZE => 21;
  2         4  
  2         102  
16 2         546 use constant DEFAULT_ALPHABETS =>
17 2     2   12 '_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  2         3  
18              
19             sub generate {
20 100006     100006 0 811713 my (%opts) = @_;
21              
22 100006   100     283562 my $size = $opts{size} // DEFAULT_SIZE;
23 100006   100     222863 my $alphabet = $opts{alphabet} // DEFAULT_ALPHABETS;
24              
25 100006         125101 my $alphabet_size = length $alphabet;
26              
27 100006 100       163201 if ( $size <= 0 ) {
28 1         100 croak 'size must be greater than zero';
29             }
30              
31 100005 100 66     250919 if ( $alphabet_size == 0 || $alphabet_size > 255 ) {
32 1         217 croak 'alphabet must not empty and contain no more than 255 chars';
33             }
34              
35 100004         719477 my @alphabet_array = split( '', $alphabet );
36 100004         219355 my $mask = ( 2 << ( log( $alphabet_size - 1 ) / log(2) ) ) - 1;
37              
38 100004         225299 my $step = ceil( 1.6 * $mask * $size / $alphabet_size );
39 100004         135810 my $id = '';
40              
41 100004         129258 while (1) {
42 100004         188942 my $bytes = [ unpack( 'C*', random_bytes($step) ) ];
43              
44 100004         9415164 for my $idx ( 0 .. $step ) {
45 2100052         2265342 my $byte;
46              
47 2100052         2598184 $byte = $bytes->[$idx] & $mask;
48              
49 2100052 50       3109022 if ( defined $alphabet_array[$byte] ) {
50 2100052         2550415 $id .= $alphabet_array[$byte];
51              
52 2100052 100       3313114 if ( length $id == $size ) {
53 100004         644092 return $id;
54             }
55             }
56             }
57             }
58              
59             }
60              
61             1;
62             __END__