POD test plus POD changes to make it pass
[p5sagit/Module-Metadata.git] / lib / Module / Metadata / Version.pm
CommitLineData
5ac756c6 1package Module::Metadata::Version;
2use strict;
3
4# stolen from Module::Build::Version - this is perl licensed code,
5# copyright them.
6
7use vars qw($VERSION);
8$VERSION = 0.77;
9
10eval "use version $VERSION";
11if ($@) { # can't locate version files, use our own
12
13 # Avoid redefined warnings if an old version.pm was available
14 delete $version::{$_} foreach keys %version::;
15
16 # first we get the stub version module
17 my $version;
18 while (<DATA>) {
19 s/(\$VERSION)\s=\s\d+/\$VERSION = 0/;
20 $version .= $_ if $_;
21 last if /^1;$/;
22 }
23
24 # and now get the current version::vpp code
25 my $vpp;
26 while (<DATA>) {
27 s/(\$VERSION)\s=\s\d+/\$VERSION = 0/;
28 $vpp .= $_ if $_;
29 last if /^1;$/;
30 }
31
32 # but we eval them in reverse order since version depends on
33 # version::vpp to already exist
34 eval $vpp; die $@ if $@;
35 $INC{'version/vpp.pm'} = 'inside Module::Metadata::Version';
36 eval $version; die $@ if $@;
37 $INC{'version.pm'} = 'inside Module::Metadata::Version';
38}
39
40# now we can safely subclass version, installed or not
41use vars qw(@ISA);
42@ISA = qw(version);
43
441;
2c11e51d 45
46=head1 NAME
47
48Module::Metadata::Version - inlined version.pm fallback for Module::Metadata
49
50=head1 DESCRIPTION
51
52This module either loads version.pm if available, or if not slurps its own
53private copy of version::vpp into memory as a fallback, then makes itself
54a subclass of whichever it found.
55
56This is a horrible hack. But so is version.pm.
57
58=head1 AUTHOR
59
60Ken Williams <kwilliams@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org>
61
62Documented by Matt S Trout (mst) <mst@shadowcat.co.uk>
63
64=head1 COPYRIGHT
65
66Copyright (c) 2001-2006 Ken Williams. All rights reserved.
67
68This library is free software; you can redistribute it and/or
69modify it under the same terms as Perl itself.
70
71=head1 SEE ALSO
72
73perl(1), L<Module::Build::ModuleInfo>(3)
74
75=cut
76
5ac756c6 77__DATA__
78# stub version module to make everything else happy
79package version;
80
81use 5.005_04;
82use strict;
83
84use vars qw(@ISA $VERSION $CLASS *declare *qv);
85
86$VERSION = 0.77;
87
88$CLASS = 'version';
89
90push @ISA, "version::vpp";
91local $^W;
92*version::qv = \&version::vpp::qv;
93*version::declare = \&version::vpp::declare;
94*version::_VERSION = \&version::vpp::_VERSION;
95if ($] > 5.009001 && $] <= 5.010000) {
96 no strict 'refs';
97 *{'version::stringify'} = \*version::vpp::stringify;
98 *{'version::(""'} = \*version::vpp::stringify;
99 *{'version::new'} = \*version::vpp::new;
100}
101
102# Preloaded methods go here.
103sub import {
104 no strict 'refs';
105 my ($class) = shift;
106
107 # Set up any derived class
108 unless ($class eq 'version') {
109 local $^W;
110 *{$class.'::declare'} = \&version::declare;
111 *{$class.'::qv'} = \&version::qv;
112 }
113
114 my %args;
115 if (@_) { # any remaining terms are arguments
116 map { $args{$_} = 1 } @_
117 }
118 else { # no parameters at all on use line
119 %args =
120 (
121 qv => 1,
122 'UNIVERSAL::VERSION' => 1,
123 );
124 }
125
126 my $callpkg = caller();
127
128 if (exists($args{declare})) {
129 *{$callpkg."::declare"} =
130 sub {return $class->declare(shift) }
131 unless defined(&{$callpkg.'::declare'});
132 }
133
134 if (exists($args{qv})) {
135 *{$callpkg."::qv"} =
136 sub {return $class->qv(shift) }
137 unless defined(&{"$callpkg\::qv"});
138 }
139
140 if (exists($args{'UNIVERSAL::VERSION'})) {
141 local $^W;
142 *UNIVERSAL::VERSION = \&version::_VERSION;
143 }
144
145 if (exists($args{'VERSION'})) {
146 *{$callpkg."::VERSION"} = \&version::_VERSION;
147 }
148}
149
1501;
151
152# replace everything from here to the end with the current version/vpp.pm
153package version::vpp;
154use strict;
155
156use POSIX qw/locale_h/;
157use locale;
158use vars qw ($VERSION @ISA @REGEXS);
159$VERSION = '0.77';
160$VERSION = eval $VERSION;
161
162push @REGEXS, qr/
163 ^v? # optional leading 'v'
164 (\d*) # major revision not required
165 \. # requires at least one decimal
166 (?:(\d+)\.?){1,}
167 /x;
168
169use overload (
170 '""' => \&stringify,
171 '0+' => \&numify,
172 'cmp' => \&vcmp,
173 '<=>' => \&vcmp,
174 'bool' => \&vbool,
175 'nomethod' => \&vnoop,
176);
177
178my $VERSION_MAX = 0x7FFFFFFF;
179
180eval "use warnings";
181if ($@) {
182 eval '
183 package warnings;
184 sub enabled {return $^W;}
185 1;
186 ';
187}
188
189sub new
190{
191 my ($class, $value) = @_;
192 my $self = bless ({}, ref ($class) || $class);
193
194 if ( ref($value) && eval('$value->isa("version")') ) {
195 # Can copy the elements directly
196 $self->{version} = [ @{$value->{version} } ];
197 $self->{qv} = 1 if $value->{qv};
198 $self->{alpha} = 1 if $value->{alpha};
199 $self->{original} = ''.$value->{original};
200 return $self;
201 }
202
203 my $currlocale = setlocale(LC_ALL);
204
205 # if the current locale uses commas for decimal points, we
206 # just replace commas with decimal places, rather than changing
207 # locales
208 if ( localeconv()->{decimal_point} eq ',' ) {
209 $value =~ tr/,/./;
210 }
211
212 if ( not defined $value or $value =~ /^undef$/ ) {
213 # RT #19517 - special case for undef comparison
214 # or someone forgot to pass a value
215 push @{$self->{version}}, 0;
216 $self->{original} = "0";
217 return ($self);
218 }
219
220 if ( $#_ == 2 ) { # must be CVS-style
221 $value = 'v'.$_[2];
222 }
223
224 $value = _un_vstring($value);
225
226 # exponential notation
227 if ( $value =~ /\d+.?\d*e[-+]?\d+/ ) {
228 $value = sprintf("%.9f",$value);
229 $value =~ s/(0+)$//; # trim trailing zeros
230 }
231
232 # This is not very efficient, but it is morally equivalent
233 # to the XS code (as that is the reference implementation).
234 # See vutil/vutil.c for details
235 my $qv = 0;
236 my $alpha = 0;
237 my $width = 3;
238 my $saw_period = 0;
239 my $vinf = 0;
240 my ($start, $last, $pos, $s);
241 $s = 0;
242
243 while ( substr($value,$s,1) =~ /\s/ ) { # leading whitespace is OK
244 $s++;
245 }
246
247 if (substr($value,$s,1) eq 'v') {
248 $s++; # get past 'v'
249 $qv = 1; # force quoted version processing
250 }
251
252 $start = $last = $pos = $s;
253
254 # pre-scan the input string to check for decimals/underbars
255 while ( substr($value,$pos,1) =~ /[._\d,]/ ) {
256 if ( substr($value,$pos,1) eq '.' ) {
257 if ($alpha) {
258 Carp::croak("Invalid version format ".
259 "(underscores before decimal)");
260 }
261 $saw_period++;
262 $last = $pos;
263 }
264 elsif ( substr($value,$pos,1) eq '_' ) {
265 if ($alpha) {
266 require Carp;
267 Carp::croak("Invalid version format ".
268 "(multiple underscores)");
269 }
270 $alpha = 1;
271 $width = $pos - $last - 1; # natural width of sub-version
272 }
273 elsif ( substr($value,$pos,1) eq ','
274 and substr($value,$pos+1,1) =~ /[0-9]/ ) {
275 # looks like an unhandled locale
276 $saw_period++;
277 $last = $pos;
278 }
279 $pos++;
280 }
281
282 if ( $alpha && !$saw_period ) {
283 require Carp;
284 Carp::croak("Invalid version format ".
285 "(alpha without decimal)");
286 }
287
288 if ( $alpha && $saw_period && $width == 0 ) {
289 require Carp;
290 Carp::croak("Invalid version format ".
291 "(misplaced _ in number)");
292 }
293
294 if ( $saw_period > 1 ) {
295 $qv = 1; # force quoted version processing
296 }
297
298 $last = $pos;
299 $pos = $s;
300
301 if ( $qv ) {
302 $self->{qv} = 1;
303 }
304
305 if ( $alpha ) {
306 $self->{alpha} = 1;
307 }
308
309 if ( !$qv && $width < 3 ) {
310 $self->{width} = $width;
311 }
312
313 while ( substr($value,$pos,1) =~ /\d/ ) {
314 $pos++;
315 }
316
317 if ( substr($value,$pos,1) !~ /[a-z]/ ) { ### FIX THIS ###
318 my $rev;
319
320 while (1) {
321 $rev = 0;
322 {
323
324 # this is atoi() that delimits on underscores
325 my $end = $pos;
326 my $mult = 1;
327 my $orev;
328
329 # the following if() will only be true after the decimal
330 # point of a version originally created with a bare
331 # floating point number, i.e. not quoted in any way
332 if ( !$qv && $s > $start && $saw_period == 1 ) {
333 $mult *= 100;
334 while ( $s < $end ) {
335 $orev = $rev;
336 $rev += substr($value,$s,1) * $mult;
337 $mult /= 10;
338 if ( abs($orev) > abs($rev)
339 || abs($rev) > abs($VERSION_MAX) ) {
340 if ( warnings::enabled("overflow") ) {
341 require Carp;
342 Carp::carp("Integer overflow in version");
343 }
344 $s = $end - 1;
345 $rev = $VERSION_MAX;
346 }
347 $s++;
348 if ( substr($value,$s,1) eq '_' ) {
349 $s++;
350 }
351 }
352 }
353 else {
354 while (--$end >= $s) {
355 $orev = $rev;
356 $rev += substr($value,$end,1) * $mult;
357 $mult *= 10;
358 if ( abs($orev) > abs($rev)
359 || abs($rev) > abs($VERSION_MAX) ) {
360 if ( warnings::enabled("overflow") ) {
361 require Carp;
362 Carp::carp("Integer overflow in version");
363 }
364 $end = $s - 1;
365 $rev = $VERSION_MAX;
366 }
367 }
368 }
369 }
370
371 # Append revision
372 push @{$self->{version}}, $rev;
373 if ( substr($value,$pos,1) eq '.'
374 && substr($value,$pos+1,1) =~ /\d/ ) {
375 $s = ++$pos;
376 }
377 elsif ( substr($value,$pos,1) eq '_'
378 && substr($value,$pos+1,1) =~ /\d/ ) {
379 $s = ++$pos;
380 }
381 elsif ( substr($value,$pos,1) eq ','
382 && substr($value,$pos+1,1) =~ /\d/ ) {
383 $s = ++$pos;
384 }
385 elsif ( substr($value,$pos,1) =~ /\d/ ) {
386 $s = $pos;
387 }
388 else {
389 $s = $pos;
390 last;
391 }
392 if ( $qv ) {
393 while ( substr($value,$pos,1) =~ /\d/ ) {
394 $pos++;
395 }
396 }
397 else {
398 my $digits = 0;
399 while (substr($value,$pos,1) =~ /[\d_]/ && $digits < 3) {
400 if ( substr($value,$pos,1) ne '_' ) {
401 $digits++;
402 }
403 $pos++;
404 }
405 }
406 }
407 }
408 if ( $qv ) { # quoted versions always get at least three terms
409 my $len = scalar @{$self->{version}};
410 $len = 3 - $len;
411 while ($len-- > 0) {
412 push @{$self->{version}}, 0;
413 }
414 }
415
416 if ( substr($value,$pos) ) { # any remaining text
417 if ( warnings::enabled("misc") ) {
418 require Carp;
419 Carp::carp("Version string '$value' contains invalid data; ".
420 "ignoring: '".substr($value,$pos)."'");
421 }
422 }
423
424 # cache the original value for use when stringification
425 if ( $vinf ) {
426 $self->{vinf} = 1;
427 $self->{original} = 'v.Inf';
428 }
429 else {
430 $self->{original} = substr($value,0,$pos);
431 }
432
433 return ($self);
434}
435
436*parse = \&new;
437
438sub numify
439{
440 my ($self) = @_;
441 unless (_verify($self)) {
442 require Carp;
443 Carp::croak("Invalid version object");
444 }
445 my $width = $self->{width} || 3;
446 my $alpha = $self->{alpha} || "";
447 my $len = $#{$self->{version}};
448 my $digit = $self->{version}[0];
449 my $string = sprintf("%d.", $digit );
450
451 for ( my $i = 1 ; $i < $len ; $i++ ) {
452 $digit = $self->{version}[$i];
453 if ( $width < 3 ) {
454 my $denom = 10**(3-$width);
455 my $quot = int($digit/$denom);
456 my $rem = $digit - ($quot * $denom);
457 $string .= sprintf("%0".$width."d_%d", $quot, $rem);
458 }
459 else {
460 $string .= sprintf("%03d", $digit);
461 }
462 }
463
464 if ( $len > 0 ) {
465 $digit = $self->{version}[$len];
466 if ( $alpha && $width == 3 ) {
467 $string .= "_";
468 }
469 $string .= sprintf("%0".$width."d", $digit);
470 }
471 else # $len = 0
472 {
473 $string .= sprintf("000");
474 }
475
476 return $string;
477}
478
479sub normal
480{
481 my ($self) = @_;
482 unless (_verify($self)) {
483 require Carp;
484 Carp::croak("Invalid version object");
485 }
486 my $alpha = $self->{alpha} || "";
487 my $len = $#{$self->{version}};
488 my $digit = $self->{version}[0];
489 my $string = sprintf("v%d", $digit );
490
491 for ( my $i = 1 ; $i < $len ; $i++ ) {
492 $digit = $self->{version}[$i];
493 $string .= sprintf(".%d", $digit);
494 }
495
496 if ( $len > 0 ) {
497 $digit = $self->{version}[$len];
498 if ( $alpha ) {
499 $string .= sprintf("_%0d", $digit);
500 }
501 else {
502 $string .= sprintf(".%0d", $digit);
503 }
504 }
505
506 if ( $len <= 2 ) {
507 for ( $len = 2 - $len; $len != 0; $len-- ) {
508 $string .= sprintf(".%0d", 0);
509 }
510 }
511
512 return $string;
513}
514
515sub stringify
516{
517 my ($self) = @_;
518 unless (_verify($self)) {
519 require Carp;
520 Carp::croak("Invalid version object");
521 }
522 return exists $self->{original}
523 ? $self->{original}
524 : exists $self->{qv}
525 ? $self->normal
526 : $self->numify;
527}
528
529sub vcmp
530{
531 require UNIVERSAL;
532 my ($left,$right,$swap) = @_;
533 my $class = ref($left);
534 unless ( UNIVERSAL::isa($right, $class) ) {
535 $right = $class->new($right);
536 }
537
538 if ( $swap ) {
539 ($left, $right) = ($right, $left);
540 }
541 unless (_verify($left)) {
542 require Carp;
543 Carp::croak("Invalid version object");
544 }
545 unless (_verify($right)) {
546 require Carp;
547 Carp::croak("Invalid version object");
548 }
549 my $l = $#{$left->{version}};
550 my $r = $#{$right->{version}};
551 my $m = $l < $r ? $l : $r;
552 my $lalpha = $left->is_alpha;
553 my $ralpha = $right->is_alpha;
554 my $retval = 0;
555 my $i = 0;
556 while ( $i <= $m && $retval == 0 ) {
557 $retval = $left->{version}[$i] <=> $right->{version}[$i];
558 $i++;
559 }
560
561 # tiebreaker for alpha with identical terms
562 if ( $retval == 0
563 && $l == $r
564 && $left->{version}[$m] == $right->{version}[$m]
565 && ( $lalpha || $ralpha ) ) {
566
567 if ( $lalpha && !$ralpha ) {
568 $retval = -1;
569 }
570 elsif ( $ralpha && !$lalpha) {
571 $retval = +1;
572 }
573 }
574
575 # possible match except for trailing 0's
576 if ( $retval == 0 && $l != $r ) {
577 if ( $l < $r ) {
578 while ( $i <= $r && $retval == 0 ) {
579 if ( $right->{version}[$i] != 0 ) {
580 $retval = -1; # not a match after all
581 }
582 $i++;
583 }
584 }
585 else {
586 while ( $i <= $l && $retval == 0 ) {
587 if ( $left->{version}[$i] != 0 ) {
588 $retval = +1; # not a match after all
589 }
590 $i++;
591 }
592 }
593 }
594
595 return $retval;
596}
597
598sub vbool {
599 my ($self) = @_;
600 return vcmp($self,$self->new("0"),1);
601}
602
603sub vnoop {
604 require Carp;
605 Carp::croak("operation not supported with version object");
606}
607
608sub is_alpha {
609 my ($self) = @_;
610 return (exists $self->{alpha});
611}
612
613sub qv {
614 my $value = shift;
615 my $class = 'version';
616 if (@_) {
617 $class = ref($value) || $value;
618 $value = shift;
619 }
620
621 $value = _un_vstring($value);
622 $value = 'v'.$value unless $value =~ /(^v|\d+\.\d+\.\d)/;
623 my $version = $class->new($value);
624 return $version;
625}
626
627*declare = \&qv;
628
629sub is_qv {
630 my ($self) = @_;
631 return (exists $self->{qv});
632}
633
634
635sub _verify {
636 my ($self) = @_;
637 if ( ref($self)
638 && eval { exists $self->{version} }
639 && ref($self->{version}) eq 'ARRAY'
640 ) {
641 return 1;
642 }
643 else {
644 return 0;
645 }
646}
647
648sub _un_vstring {
649 my $value = shift;
650 # may be a v-string
651 if ( $] >= 5.006_000 && length($value) >= 3 && $value !~ /[._]/ ) {
652 my $tvalue = sprintf("v%vd",$value);
653 if ( $tvalue =~ /^v\d+\.\d+\.\d+$/ ) {
654 # must be a v-string
655 $value = $tvalue;
656 }
657 }
658 return $value;
659}
660
661sub _VERSION {
662 my ($obj, $req) = @_;
663 my $class = ref($obj) || $obj;
664
665 no strict 'refs';
666 if ( exists $INC{"$class.pm"} and not %{"$class\::"} and $] >= 5.008) {
667 # file but no package
668 require Carp;
669 Carp::croak( "$class defines neither package nor VERSION"
670 ."--version check failed");
671 }
672
673 my $version = eval "\$$class\::VERSION";
674 if ( defined $version ) {
675 local $^W if $] <= 5.008;
676 $version = version::vpp->new($version);
677 }
678
679 if ( defined $req ) {
680 unless ( defined $version ) {
681 require Carp;
682 my $msg = $] < 5.006
683 ? "$class version $req required--this is only version "
684 : "$class does not define \$$class\::VERSION"
685 ."--version check failed";
686
687 if ( $ENV{VERSION_DEBUG} ) {
688 Carp::confess($msg);
689 }
690 else {
691 Carp::croak($msg);
692 }
693 }
694
695 $req = version::vpp->new($req);
696
697 if ( $req > $version ) {
698 require Carp;
699 if ( $req->is_qv ) {
700 Carp::croak(
701 sprintf ("%s version %s required--".
702 "this is only version %s", $class,
703 $req->normal, $version->normal)
704 );
705 }
706 else {
707 Carp::croak(
708 sprintf ("%s version %s required--".
709 "this is only version %s", $class,
710 $req->stringify, $version->stringify)
711 );
712 }
713 }
714 }
715
716 return defined $version ? $version->stringify : undef;
717}
718
7191; #this line is important and will help the module return a true value