File Coverage

blib/lib/Gentoo/PerlMod/Version.pm
Criterion Covered Total %
statement 109 115 94.7
branch 34 40 85.0
condition 2 2 100.0
subroutine 18 18 100.0
pod 1 1 100.0
total 164 176 93.1


line stmt bran cond sub pod time code
1 4     4   69035 use 5.006;
  4         11  
2 4     4   36 use strict;
  4         5  
  4         88  
3 4     4   16 use warnings;
  4         5  
  4         307  
4              
5             package Gentoo::PerlMod::Version;
6              
7             our $VERSION = 'v0.8.1';
8              
9             # ABSTRACT: Convert arbitrary Perl Modules' versions into normalized Gentoo versions.
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 4     4   2021 use Sub::Exporter::Progressive -setup => { exports => [qw( gentooize_version )] };
  4         3932  
  4         47  
14 4     4   2078 use version 0.77;
  4         7497  
  4         32  
15              
16             sub gentooize_version {
17 68     68 1 17999 my ( $perlver, $config ) = @_;
18 68   100     237 $config ||= {};
19 68 100       104 if ( not defined $perlver ) {
20 1         4 return _err_perlver_undefined($config);
21             }
22 67 100       150 $config->{lax} = 0 unless defined $config->{lax};
23 67 50       100 if ( _env_hasopt('always_lax') ) {
24 0         0 $config->{lax} = _env_getopt('always_lax');
25             }
26              
27 67 100       280 if ( $perlver =~ /\Av?[\d.]+\z/msx ) {
28 46         67 return _lax_cleaning_0($perlver);
29             }
30              
31 21 100       62 if ( $perlver =~ /\Av?[\d._]+(-TRIAL)?\z/msx ) {
32 13 100       21 if ( $config->{lax} > 0 ) {
33 11         18 return _lax_cleaning_1($perlver);
34             }
35 2         4 return _err_matches_trial_regex_nonlax( $perlver, $config );
36             }
37              
38 8 100       13 if ( 2 == $config->{lax} ) {
39 6         10 return _lax_cleaning_2($perlver);
40             }
41 2         5 return _err_not_decimal_or_trial( $perlver, $config );
42             }
43              
44             ###
45             #
46             # character to code translation
47             #
48             ###
49              
50             ## no critic ( ProhibitMagicNumbers )
51             my $char_map = {
52             ( map { $_ => $_ } 0 .. 9 ), # 0..9
53             ( map { chr( $_ + 65 ) => $_ + 10 } 0 .. 25 ), # A-Z
54             ( map { chr( $_ + 97 ) => $_ + 10 } 0 .. 25 ), # a-z
55             };
56              
57             # _code_for('z') -> $number
58             #
59              
60             sub _code_for {
61 25     25   1241 my $char = shift;
62 25 100       37 if ( not exists $char_map->{$char} ) {
63 1         2 my $char_ord = ord $char;
64 1         2 return _err_bad_char( $char, $char_ord );
65             }
66 24         44 return $char_map->{$char};
67             }
68              
69             ###
70             #
71             # Pair to number transformation.
72             #
73             # _enc_pair( 'x','y' ) -> $number
74             #
75             ##
76              
77             sub _enc_pair {
78 14     14   15 my (@tokens) = @_;
79 14 50       18 if ( not @tokens ) {
80 0         0 return q{};
81             }
82 14 100       20 if ( @tokens < 2 ) {
83 4         6 return _code_for( shift @tokens );
84             }
85 10         14 return ( _code_for( $tokens[0] ) * 36 ) + ( _code_for( $tokens[1] ) );
86             }
87              
88             ###
89             #
90             # String to dotted-decimal conversion
91             #
92             # $dotstring = _ascii_to_int("HELLOWORLD");
93             #
94             ###
95             sub _ascii_to_int {
96 6     6   7 my $string = shift;
97 6         9 my @chars = split //msx, $string;
98 6         5 my @output;
99              
100 6         8 while (@chars) {
101 14         20 push @output, _enc_pair( splice @chars, 0, 2, () );
102             }
103              
104 6         17 return join q{.}, @output;
105             }
106              
107             #
108             # Handler for gentooize_version( ... { lax => 0 } )
109             #
110             sub _lax_cleaning_0 {
111 46     46   35 my $version = shift;
112 46         60 return _expand_numeric($version);
113             }
114              
115             #
116             # Handler for gentooize_version( ... { lax => 1 } )
117             #
118              
119             sub _lax_cleaning_1 {
120 17     17   16 my $version = shift;
121 17         10 my $isdev = 0;
122 17         14 my $prereleasever = undef;
123              
124 17 100       33 if ( $version =~ s/-TRIAL\z//msx ) {
125 5         5 $isdev = 1;
126             }
127 17 100       45 if ( $version =~ s/_(.*)\z/$1/msx ) {
128 6         7 $prereleasever = "$1";
129 6         5 $isdev = 1;
130 6 100       10 if ( $prereleasever =~ /_/msx ) {
131 1         3 return _err_lax_multi_underscore($version);
132             }
133             }
134 16         20 $version = _expand_numeric($version);
135 16 100       26 if ($isdev) {
136 10         12 $version .= '_rc';
137             }
138 16         51 return $version;
139             }
140              
141             #
142             # Handler for gentooize_version( ... { lax => 2 } )
143             #
144              
145             sub _lax_cleaning_2 {
146 6     6   6 my $version = shift;
147 6         4 my $istrial = 0;
148              
149 6         6 my $has_v = 0;
150              
151 6 50       9 if ( $version =~ s/-TRIAL\z//msx ) {
152 0         0 $istrial = 1;
153             }
154 6 50       8 if ( $version =~ s/\Av//msx ) {
155 0         0 $has_v = 1;
156             }
157              
158 6         24 my @parts = split /([._])/msx, $version;
159 6         3 my @out;
160 6         8 for (@parts) {
161 30 100       45 if (/\A[_.]\z/msx) {
162 12         10 push @out, $_;
163 12         10 next;
164             }
165 18 100       24 if (/\A\d\z/msx) {
166 12         11 push @out, $_;
167 12         7 next;
168             }
169 6         8 push @out, _ascii_to_int($_);
170             }
171              
172 6         7 my $version_out = join q{}, @out;
173 6 50       10 if ($istrial) {
174 0         0 $version_out .= '-TRIAL';
175             }
176 6 50       10 if ($has_v) {
177 0         0 $version_out = 'v' . $version_out;
178             }
179 6         28 return _lax_cleaning_1($version_out);
180             }
181              
182             #
183             # Expands dotted decimal to a float, and then chunks the float.
184             #
185             # my $clean = _expand_numeric( $dirty );
186             #
187             sub _expand_numeric {
188 62     62   45 my $perlver = shift;
189              
190 62         474 my $ver = version->parse($perlver)->normal;
191              
192 62         198 $ver =~ s/\Av//msx; # strip leading v
193              
194 62         132 my @tokens = split /[.]/msx, $ver;
195 62         46 my @out;
196              
197 62         72 for (@tokens) {
198 203         134 s/\A0+([1-9])/$1/msx; # strip leading 0's
199 203         190 push @out, $_;
200             }
201              
202 62         302 return join q{.}, @out;
203             }
204              
205             BEGIN {
206 4     4   8 for my $err (qw( perlver_undefined matches_trial_regex_nonlax not_decimal_or_trial bad_char lax_multi_underscore )) {
207             my $code = sub {
208 7     7   399 require Gentoo::PerlMod::Version::Error;
209 7         37 my $sub = Gentoo::PerlMod::Version::Error->can($err);
210 7         17 goto $sub;
211 20         59 };
212             ## no critic ( ProhibitNoStrict )
213 4     4   4782 no strict 'refs';
  4         8  
  4         385  
214 20         19 *{ __PACKAGE__ . '::_err_' . $err } = $code;
  20         62  
215             }
216 4         6 for my $env (qw( opts hasopt getopt )) {
217             my $code = sub {
218 67     67   1363 require Gentoo::PerlMod::Version::Env;
219 67         210 my $sub = Gentoo::PerlMod::Version::Env->can($env);
220 67         155 goto $sub;
221 12         58 };
222             ## no critic ( ProhibitNoStrict )
223              
224 4     4   18 no strict 'refs';
  4         6  
  4         176  
225 12         39 *{ __PACKAGE__ . '::_env_' . $env } = $code;
  12         137  
226             }
227              
228             }
229              
230             1;
231              
232             __END__