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   227818 use 5.008001;
  2         12  
3 2     2   11 use strict;
  2         2  
  2         36  
4 2     2   9 use warnings;
  2         21  
  2         76  
5              
6             our $VERSION = "0.02";
7              
8 2     2   10 use strict;
  2         3  
  2         55  
9 2     2   18 use warnings;
  2         4  
  2         79  
10              
11 2     2   13 use POSIX qw(ceil);
  2         3  
  2         22  
12 2     2   3387 use Carp qw(croak);
  2         4  
  2         109  
13 2     2   1174 use Bytes::Random::Secure qw(random_bytes);
  2         19826  
  2         123  
14              
15 2     2   15 use constant DEFAULT_SIZE => 21;
  2         3  
  2         156  
16 2         511 use constant DEFAULT_ALPHABETS =>
17 2     2   14 '_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  2         4  
18              
19             sub generate {
20 100006     100006 0 737618 my (%opts) = @_;
21              
22 100006   100     266438 my $size = $opts{size} // DEFAULT_SIZE;
23 100006   100     207457 my $alphabet = $opts{alphabet} // DEFAULT_ALPHABETS;
24              
25 100006         114245 my $alphabet_size = length $alphabet;
26              
27 100006 100       164356 if ( $size <= 0 ) {
28 1         100 croak 'size must be greater than zero';
29             }
30              
31 100005 100 66     245692 if ( $alphabet_size == 0 || $alphabet_size > 255 ) {
32 1         189 croak 'alphabet must not empty and contain no more than 255 chars';
33             }
34              
35 100004         714449 my @alphabet_array = split( '', $alphabet );
36 100004         228534 my $mask = ( 2 << ( log( $alphabet_size - 1 ) / log(2) ) ) - 1;
37              
38 100004         234280 my $step = ceil( 1.6 * $mask * $size / $alphabet_size );
39 100004         136209 my $id = '';
40              
41 100004         116713 while (1) {
42 100004         172652 my $bytes = [ unpack( 'C*', random_bytes($step) ) ];
43              
44 100004         9001836 for my $idx ( 0 .. $step ) {
45 2100052         2183627 my $byte;
46              
47 2100052         2390050 $byte = $bytes->[$idx] & $mask;
48              
49 2100052 50       3136185 if ( defined $alphabet_array[$byte] ) {
50 2100052         2524992 $id .= $alphabet_array[$byte];
51              
52 2100052 100       3228876 if ( length $id == $size ) {
53 100004         652487 return $id;
54             }
55             }
56             }
57             }
58              
59             }
60              
61             1;
62             __END__