File Coverage

lib/PortageXS/Version.pm
Criterion Covered Total %
statement 15 92 16.3
branch 0 36 0.0
condition 0 23 0.0
subroutine 6 13 46.1
pod 5 5 100.0
total 26 169 15.3


line stmt bran cond sub pod time code
1             package PortageXS::Version;
2             BEGIN {
3 5     5   168 $PortageXS::Version::AUTHORITY = 'cpan:KENTNL';
4             }
5             {
6             $PortageXS::Version::VERSION = '0.3.1';
7             }
8              
9             # ABSTRACT: Gentoo version object
10              
11 5     5   29 use strict;
  5         11  
  5         149  
12 5     5   25 use warnings;
  5         9  
  5         138  
13              
14              
15              
16 5     5   28 use Scalar::Util ();
  5         8  
  5         200  
17              
18             use overload (
19 5         48 '<=>' => \&_spaceship,
20             '""' => \&_stringify,
21 5     5   23 );
  5         7  
22              
23             my $int_rx = qr/[0-9]+/;
24             my $letter_rx = qr/[a-zA-Z]/;
25             my $dotted_num_rx = qr/$int_rx(?:\.$int_rx)*/o;
26              
27             my @suffixes = qw;
28             my $suffix_rx = join '|', grep !/^normal$/, @suffixes;
29             $suffix_rx = qr/(?:$suffix_rx)/o;
30              
31             our $version_rx = qr{
32             $dotted_num_rx $letter_rx?
33             (?:_$suffix_rx$int_rx?)*
34             (?:-r$int_rx)?
35             }xo;
36              
37             my $capturing_version_rx = qr{
38             ($dotted_num_rx) ($letter_rx)?
39             ((?:_$suffix_rx$int_rx?)*)
40             (?:-r($int_rx))?
41             }xo;
42              
43              
44             sub new {
45 0     0 1   my $class = shift;
46 0   0       $class = ref($class) || $class;
47              
48 0           my $vstring = shift;
49 0 0         if (defined $vstring) {
50 0           $vstring =~ s/^[._]+//g;
51 0           $vstring =~ s/[._]+$//g;
52              
53 0 0         if ($vstring =~ /^$capturing_version_rx$/o) {
54 0           return bless {
55             string => $vstring,
56             version => [ split /\.+/, $1 ],
57             letter => $2,
58             suffixes => [ map /_($suffix_rx)($int_rx)?/go, $3 ],
59             revision => $4,
60             }, $class;
61             }
62              
63 0           require Carp;
64 0           Carp::croak("Couldn't parse version string '$vstring'");
65             }
66              
67 0           require Carp;
68 0           Carp::croak('You must specify a version string');
69             }
70              
71             my @parts;
72             BEGIN {
73 5     5   2380 @parts = qw;
74 5     0 1 4469 eval "sub $_ { \$_[0]->{$_} }" for @parts;
  0     0 1    
  0     0 1    
  0     0 1    
  0            
75             }
76              
77              
78             my %suffix_grade = do {
79             my $i = 0;
80             map { $_ => ++$i } @suffixes;
81             };
82              
83             sub _spaceship {
84 0     0     my ($v1, $v2, $r) = @_;
85              
86 0 0 0       unless (Scalar::Util::blessed($v2) and $v2->isa(__PACKAGE__)) {
87 0           $v2 = $v1->new($v2);
88             }
89              
90 0 0         ($v1, $v2) = ($v2, $v1) if $r;
91              
92             {
93 0           my @a = @{ $v1->version };
  0            
  0            
94 0           my @b = @{ $v2->version };
  0            
95              
96             {
97 0           my $x = shift @a;
  0            
98 0           my $y = shift @b;
99 0           my $c = $x <=> $y;
100 0 0         return $c if $c;
101             }
102              
103 0   0       while (@a and @b) {
104 0           my $x = shift @a;
105 0           my $y = shift @b;
106 0           my $c;
107 0 0 0       if ($x =~ /^0/ or $y =~ /^0/) {
108 0           s/0+\z// for $x, $y;
109 0           $c = $x cmp $y;
110             } else {
111 0           $c = $x <=> $y;
112             }
113 0 0         return $c if $c;
114             }
115              
116 0 0         return 1 if @a;
117 0 0         return -1 if @b;
118             }
119              
120             {
121 0 0         my ($l1, $l2) = map { defined() ? ord : 0 } map $_->letter, $v1, $v2;
  0            
  0            
122              
123 0           my $c = $l1 <=> $l2;
124 0 0         return $c if $c;
125             }
126              
127             {
128 0           my @a = @{ $v1->suffixes };
  0            
  0            
129 0           my @b = @{ $v2->suffixes };
  0            
130              
131 0   0       while (@a or @b) {
132 0   0       my $x = $suffix_grade{ shift(@a) || 'normal' };
133 0   0       my $y = $suffix_grade{ shift(@b) || 'normal' };
134 0           my $c = $x <=> $y;
135 0 0         return $c if $c;
136              
137 0   0       $x = shift(@a) || 0;
138 0   0       $y = shift(@b) || 0;
139 0           $c = $x <=> $y;
140 0 0         return $c if $c;
141             }
142             }
143              
144             {
145 0 0         my ($r1, $r2) = map { defined() ? $_ : 0 } map $_->revision, $v1, $v2;
  0            
  0            
146              
147 0           my $c = $r1 <=> $r2;
148 0 0         return $c if $c;
149             }
150              
151 0           return 0;
152             }
153              
154             sub _stringify {
155 0     0     my ($v) = @_;
156              
157 0           my ($version, $letter, $suffixes, $revision) = map $v->$_, @parts;
158 0           my @suffixes = @$suffixes;
159              
160 0           $version = join '.', @$version;
161 0 0         $version .= $letter if defined $letter;
162 0           while (my @suffix = splice @suffixes, 0, 2) {
163 0           my $s = $suffix[0];
164 0           my $n = $suffix[1];
165 0 0         $version .= "_$s" . (defined $n ? $n : '');
166             }
167 0 0         $version .= "-r$revision" if defined $revision;
168              
169 0           $version;
170             }
171              
172              
173             1; # End of PortageXS::Version
174              
175             __END__