File Coverage

blib/lib/Person/ID/CZ/RC/Generator.pm
Criterion Covered Total %
statement 60 80 75.0
branch 10 32 31.2
condition 1 3 33.3
subroutine 12 14 85.7
pod 2 2 100.0
total 85 131 64.8


line stmt bran cond sub pod time code
1             package Person::ID::CZ::RC::Generator;
2              
3             # Pragmas.
4 5     5   73757 use strict;
  5         11  
  5         191  
5 5     5   29 use warnings;
  5         9  
  5         162  
6              
7             # Modules.
8 5     5   4690 use Class::Utils qw(set_params);
  5         77134  
  5         109  
9 5     5   7475 use DateTime;
  5         1009712  
  5         248  
10 5     5   58 use English qw(-no_match_vars);
  5         21  
  5         50  
11 5     5   2964 use Error::Pure qw(err);
  5         51  
  5         262  
12 5     5   29 use List::MoreUtils qw(none);
  5         13  
  5         263  
13 5     5   4745 use Random::Day;
  5         370433  
  5         180  
14 5     5   64 use Readonly;
  5         13  
  5         4984  
15              
16             # Constants.
17             Readonly::Scalar our $EMPTY_STR => q{};
18             Readonly::Scalar our $YEAR_FROM => 1855;
19             Readonly::Scalar our $YEAR_TO => 2054;
20              
21             # Version.
22             our $VERSION = 0.03;
23              
24             # Constructor.
25             sub new {
26 4     4 1 4986 my ($class, @params) = @_;
27              
28             # Create object.
29 4         14 my $self = bless {}, $class;
30              
31             # Alternate flag.
32 4         18 $self->{'alternate'} = undef;
33              
34             # Day.
35 4         8 $self->{'day'} = undef;
36              
37             # Month.
38 4         10 $self->{'month'} = undef;
39              
40             # RC number separator.
41 4         10 $self->{'rc_sep'} = $EMPTY_STR;
42              
43             # Serial.
44 4         8 $self->{'serial'} = undef;
45              
46             # Sex.
47 4         7 $self->{'sex'} = undef;
48              
49             # Year.
50 4         16 $self->{'year'} = undef;
51              
52             # Process parameters.
53 4         21 set_params($self, @params);
54              
55             # Check RC separator.
56 2 50   2   394 if (none { $self->{'rc_sep'} eq $_ } ('', '/')) {
  2         14  
57 0         0 err "Parameter 'rc_sep' has bad value.";
58             }
59              
60             # Check serial part of RC.
61 2 50       15 if (defined $self->{'serial'}) {
62 0 0       0 if ($self->{'serial'} !~ m/^\d+$/ms) {
    0          
    0          
63 0         0 err "Parameter 'serial' isn't number.";
64             } elsif ($self->{'serial'} < 1) {
65 0         0 err "Parameter 'serial' is lesser than 1.";
66             } elsif ($self->{'serial'} > 999) {
67 0         0 err "Parameter 'serial' is greater than 999.";
68             }
69             }
70              
71             # Check sex.
72 2 50 33     13 if (defined $self->{'sex'}
73 0     0   0 && none { $self->{'sex'} eq $_ } qw(male female)) {
74              
75 0         0 err "Parameter 'sex' has bad value.";
76             }
77              
78             # Check year.
79 2 50       8 if (defined $self->{'year'}) {
80 0 0       0 if ($self->{'year'} < $YEAR_FROM) {
    0          
81 0         0 err "Parameter 'year' is lesser than $YEAR_FROM.";
82             } elsif ($self->{'year'} > $YEAR_TO) {
83 0         0 err "Parameter 'year' is greater than $YEAR_TO.";
84             }
85             }
86              
87             # Object.
88 2         7 return $self;
89             }
90              
91             # Get rc.
92             sub rc {
93 1     1 1 5 my $self = shift;
94              
95             # Construct date.
96 1         10 my $date = Random::Day->new(
97             'day' => $self->{'day'},
98             'dt_from' => DateTime->new(
99             'day' => 1,
100             'month' => 1,
101             'year' => $YEAR_FROM,
102             ),
103             'dt_to' => DateTime->new(
104             'day' => 31,
105             'month' => 12,
106             'year' => $YEAR_TO,
107             ),
108             'month' => $self->{'month'},
109             'year' => $self->{'year'},
110             )->get;
111              
112             # Sex.
113 1         6129 my $sex = $self->{'sex'};
114 1 50       4 if (! defined $sex) {
115 1 50       5 $sex = int(rand(2)) ? 'male' : 'female';
116             }
117              
118             # Get month part.
119 1         4 my $month = $date->month;
120 1 50       6 if ($sex eq 'female') {
121 1         2 $month += 50;
122             }
123              
124             # Alternate number.
125 1 50       3 if ($self->{'alternate'}) {
126 0         0 $month += 20;
127             }
128              
129             # Construct date part.
130 1         4 my $date_part = (sprintf '%02d%02d%02d', (substr $date->year, 2), $month, $date->day);
131              
132             # Add serial.
133 1         34 my $serial = $self->{'serial'};
134 1 50       2 if (! defined $serial) {
135 1         2 $serial = int(rand(1000)) + 1;
136             }
137 1         3 my $serial_part = sprintf '%03d', $serial;
138              
139             # Add checksum.
140 1 50       3 if ($date->year > 1954) {
141 0         0 $serial_part = $self->_checksum($date_part, $serial_part);
142             }
143              
144             # Construct rc.
145 1         7 my $rc = $date_part.$self->{'rc_sep'}.$serial_part;
146              
147             # Return $rc.
148 1         6 return $rc;
149             }
150              
151             # Compute checksum.
152             sub _checksum {
153 0     0     my ($self, $date_part, $serial_part) = @_;
154 0           my $num = $date_part.$serial_part;
155 0           my $num_11 = $num % 11;
156 0           my $checksum;
157 0 0         if ($num_11 == 10) {
158 0           $checksum = 0;
159             } else {
160 0           $checksum = $num_11;
161             }
162 0           return $serial_part.$checksum;
163             }
164              
165             1;
166              
167             __END__