]> git.vpit.fr Git - perl/modules/CPANPLUS-Dist-Gentoo.git/blob - lib/CPANPLUS/Dist/Gentoo/Version.pm
Bump copyright year
[perl/modules/CPANPLUS-Dist-Gentoo.git] / lib / CPANPLUS / Dist / Gentoo / Version.pm
1 package CPANPLUS::Dist::Gentoo::Version;
2
3 use strict;
4 use warnings;
5
6 =head1 NAME
7
8 CPANPLUS::Dist::Gentoo::Version - Gentoo version object.
9
10 =head1 VERSION
11
12 Version 0.11
13
14 =cut
15
16 our $VERSION = '0.11';
17
18 =head1 DESCRIPTION
19
20 This class models Gentoo versions as described in L<http://devmanual.gentoo.org/ebuild-writing/file-format/index.html>.
21
22 =cut
23
24 use Scalar::Util ();
25
26 use overload (
27  '<=>' => \&_spaceship,
28  '""'  => \&_stringify,
29 );
30
31 my $int_rx        = qr/[0-9]+/;
32 my $letter_rx     = qr/[a-zA-Z]/;
33 my $dotted_num_rx = qr/$int_rx(?:\.$int_rx)*/o;
34
35 my @suffixes  = qw<alpha beta pre rc normal p>;
36 my $suffix_rx = join '|', grep !/^normal$/, @suffixes;
37 $suffix_rx    = qr/(?:$suffix_rx)/o;
38
39 our $version_rx = qr{
40  $dotted_num_rx $letter_rx?
41  (?:_$suffix_rx$int_rx?)*
42  (?:-r$int_rx)?
43 }xo;
44
45 my $capturing_version_rx = qr{
46  ($dotted_num_rx) ($letter_rx)?
47  ((?:_$suffix_rx$int_rx?)*)
48  (?:-r($int_rx))?
49 }xo;
50
51 =head1 METHODS
52
53 =head2 C<new $vstring>
54
55 Creates a new L<CPANPLUS::Dist::Gentoo::Version> object from the version string C<$vstring>.
56
57 =cut
58
59 sub new {
60  my $class = shift;
61  $class = ref($class) || $class;
62
63  my $vstring = shift;
64  if (defined $vstring) {
65   $vstring =~ s/^[._]+//g;
66   $vstring =~ s/[._]+$//g;
67
68   if ($vstring =~ /^$capturing_version_rx$/o) {
69    return bless {
70     string   => $vstring,
71     version  => [ split /\.+/, $1 ],
72     letter   => $2,
73     suffixes => [ map /_($suffix_rx)($int_rx)?/go, $3 ],
74     revision => $4,
75    }, $class;
76   }
77
78   require Carp;
79   Carp::croak("Couldn't parse version string '$vstring'");
80  }
81
82  require Carp;
83  Carp::croak('You must specify a version string');
84 }
85
86 my @parts;
87 BEGIN {
88  @parts = qw<version letter suffixes revision>;
89  eval "sub $_ { \$_[0]->{$_} }" for @parts;
90 }
91
92 =head2 C<version>
93
94 Read-only accessor for the C<version> part of the version object.
95
96 =head2 C<letter>
97
98 Read-only accessor for the C<letter> part of the version object.
99
100 =head2 C<suffixes>
101
102 Read-only accessor for the C<suffixes> part of the version object.
103
104 =head2 C<revision>
105
106 Read-only accessor for the C<revision> part of the version object.
107
108 =cut
109
110 my %suffix_grade = do {
111  my $i = 0;
112  map { $_ => ++$i } @suffixes;
113 };
114
115 sub _spaceship {
116  my ($v1, $v2, $r) = @_;
117
118  unless (Scalar::Util::blessed($v2) and $v2->isa(__PACKAGE__)) {
119   $v2 = $v1->new($v2);
120  }
121
122  ($v1, $v2) = ($v2, $v1) if $r;
123
124  {
125   my @a = @{ $v1->version };
126   my @b = @{ $v2->version };
127
128   {
129    my $x = shift @a;
130    my $y = shift @b;
131    my $c = $x <=> $y;
132    return $c if $c;
133   }
134
135   while (@a and @b) {
136    my $x = shift @a;
137    my $y = shift @b;
138    my $c;
139    if ($x =~ /^0/ or $y =~ /^0/) {
140     s/0+\z// for $x, $y;
141     $c = $x cmp $y;
142    } else {
143     $c = $x <=> $y;
144    }
145    return $c if $c;
146   }
147
148   return  1 if @a;
149   return -1 if @b;
150  }
151
152  {
153   my ($l1, $l2) = map { defined() ? ord : 0 } map $_->letter, $v1, $v2;
154
155   my $c = $l1 <=> $l2;
156   return $c if $c;
157  }
158
159  {
160   my @a = @{ $v1->suffixes };
161   my @b = @{ $v2->suffixes };
162
163   while (@a or @b) {
164    my $x = $suffix_grade{ shift(@a) || 'normal' };
165    my $y = $suffix_grade{ shift(@b) || 'normal' };
166    my $c = $x <=> $y;
167    return $c if $c;
168
169    $x = shift(@a) || 0;
170    $y = shift(@b) || 0;
171    $c = $x <=> $y;
172    return $c if $c;
173   }
174  }
175
176  {
177   my ($r1, $r2) = map { defined() ? $_ : 0 } map $_->revision, $v1, $v2;
178
179   my $c = $r1 <=> $r2;
180   return $c if $c;
181  }
182
183  return 0;
184 }
185
186 sub _stringify {
187  my ($v) = @_;
188
189  my ($version, $letter, $suffixes, $revision) = map $v->$_, @parts;
190  my @suffixes = @$suffixes;
191
192  $version   = join '.', @$version;
193  $version  .= $letter if defined $letter;
194  while (my @suffix = splice @suffixes, 0, 2) {
195   my $s = $suffix[0];
196   my $n = $suffix[1];
197   $version .= "_$s" . (defined $n ? $n : '');
198  }
199  $version .= "-r$revision" if defined $revision;
200
201  $version;
202 }
203
204 =pod
205
206 This class provides overloaded methods for numerical comparison and stringification.
207
208 =head1 SEE ALSO
209
210 L<CPANPLUS::Dist::Gentoo>.
211
212 =head1 AUTHOR
213
214 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
215
216 You can contact me by mail or on C<irc.perl.org> (vincent).
217
218 =head1 BUGS
219
220 Please report any bugs or feature requests to C<bug-cpanplus-dist-gentoo at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=CPANPLUS-Dist-Gentoo>.
221 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
222
223 =head1 SUPPORT
224
225 You can find documentation for this module with the perldoc command.
226
227     perldoc CPANPLUS::Dist::Gentoo
228
229 =head1 COPYRIGHT & LICENSE
230
231 Copyright 2009,2010,2011,2012 Vincent Pit, all rights reserved.
232
233 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
234
235 =cut
236
237 1; # End of CPANPLUS::Dist::Gentoo::Version