File Coverage

blib/lib/Business/BR/RG.pm
Criterion Covered Total %
statement 58 61 95.0
branch 20 28 71.4
condition 9 9 100.0
subroutine 12 12 100.0
pod 5 5 100.0
total 104 115 90.4


line stmt bran cond sub pod time code
1 2     2   47839 use strict;
  2         6  
  2         73  
2 2     2   11 use warnings;
  2         4  
  2         73  
3              
4             package Business::BR::RG;
5              
6 2     2   55 use 5.004;
  2         6  
  2         340  
7 2     2   10 use strict;
  2         3  
  2         57  
8 2     2   8 use warnings;
  2         3  
  2         1699  
9              
10             require Exporter;
11              
12             our @ISA = qw(Exporter);
13              
14             our $VERSION = 0.001;
15              
16             #our %EXPORT_TAGS = ( 'all' => [ qw() ] );
17             #our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
18             #our @EXPORT = qw();
19              
20             our @EXPORT_OK = qw( canon_rg format_rg parse_rg random_rg );
21             our @EXPORT = qw( test_rg );
22              
23             # tambem tive que copiar o _dot do Business::BR::Ids::Common pois o valor de X é 10
24             sub _dot {
25 211     211   316 my $a = shift;
26 211         238 my $b = shift;
27 211 50       524 warn "arguments a and b should have the same length"
28             unless ( @$a == @$b );
29 211         290 my $s = 0;
30 211         232 my $c = @$a;
31 211         380 for my $i ( 0 .. $c ) {
32 2010         2886 my ( $x, $y ) = ( $a->[$i], $b->[$i] );
33 2010 100 100     6932 if ( $x && $y ) {
34 1614 100       2892 $y = 10 if ( $y eq 'X' );
35              
36 1614         2772 $s += $x * $y;
37             }
38             }
39 211         642 return $s;
40             }
41              
42             # o RG tem pode ter o digito X que representa o numero 10, portanto, nao pude usar o
43             # _canon_id do Business::BR::Ids::Common
44             # the RG may have an X, thats represents 10, because of this, I use self functions for _dot and for clean
45             sub canon_rg {
46 215     215 1 324 my $rg = uc shift();
47              
48 215 50       388 if ($rg) {
49              
50 215         396 $rg =~ s/[^X\d]//go;
51              
52 215 50       372 if ( length($rg) == 9 ) {
53 215         523 return $rg;
54             }
55             else {
56 0         0 return sprintf( '%0*s', 9, $rg );
57             }
58              
59             }
60 0         0 return undef;
61             }
62              
63             # there is a subtle difference here between the return for
64             # for an input which is not 9 digits long (undef)
65             # and one that does not satisfy the check equations (0).
66             # Correct RG numbers return 1.
67             sub test_rg {
68 111     111 1 387 my $rg = canon_rg shift;
69 111 50       225 return undef if length $rg != 9;
70              
71 111         441 my @rg = split '', $rg;
72              
73 111         343 my $mod = _dot( [ 2, 3, 4, 5, 6, 7, 8, 9, 100 ], \@rg ) % 11;
74              
75 111 100       586 return $mod == 0 ? 1 : 0;
76             }
77              
78             sub format_rg {
79 101     101 1 181 my $rg = canon_rg shift;
80 101         1015 $rg =~ s/^(..)(...)(...)(.)/$1.$2.$3-$4/;
81 101         494 return $rg;
82             }
83              
84             sub parse_rg {
85 2     2 1 987 my $rg = canon_rg shift;
86 2         10 my ( $base, $dv ) = $rg =~ /(\d{8})(\d|X)/;
87 2 100       7 if (wantarray) {
88 1         4 return ( $base, $dv );
89             }
90 1         7 return { base => $base, dv => $dv };
91             }
92              
93             # computes the check digits of the candidate RG number given as argument
94             # (only the first 8 digits enter the computation)
95             #
96             # In list context, it returns the check digit.
97             # In scalar context, it returns the complete RG (base and check digit)
98             sub _dv_rg {
99 100     100   115 my $base = shift; # expected to be canon'ed already ?!
100 100 50       246 my $valid = @_ ? shift : 1;
101 100 100       171 my $dev = $valid ? 0 : 2; # deviation (to make RG invalid)
102              
103 100         515 my @base = split '', substr( $base, 0, 8 );
104              
105 100         370 my $dv = ( -_dot( [ 2, 3, 4, 5, 6, 7, 8, 9 ], \@base ) + $dev ) % 11 % 10;
106              
107 100 100 100     584 if ( $dv == 0 && $valid && test_rg( $base . $dv ) == 0 ) {
      100        
108 5         26 $dv = 'X';
109             }
110              
111 100 50       183 return ($dv) if wantarray;
112              
113 100 50       185 if ( length($base) == 9 ) {
114 0         0 substr( $base, 9, 1 ) = $dv;
115             }
116             else {
117 100         136 $base .= $dv;
118             }
119              
120 100         415 return $base;
121             }
122              
123             # generates a random (correct or incorrect) RG
124             # $rg = rand_rg();
125             # $rg = rand_rg($valid);
126             #
127             # if $valid==0, produces an invalid . RG
128             sub random_rg {
129 100 50   100 1 54630 my $valid = @_ ? shift : 1; # valid RG by default
130              
131 100         483 my $base = sprintf '%08s', int( rand(1E8) ); # 8 dígitos
132              
133 100         174 return scalar _dv_rg( $base, $valid );
134             }
135              
136             1;
137              
138             __END__