From: Rafael Garcia-Suarez Date: Thu, 15 Sep 2005 14:19:19 +0000 (+0000) Subject: Upgrade to version.pm 0.48 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=cb5772bbb31a56af73775120008b21214f3fccb5;p=p5sagit%2Fp5-mst-13.2.git Upgrade to version.pm 0.48 p4raw-id: //depot/perl@25416 --- diff --git a/MANIFEST b/MANIFEST index 74cf6a9..dadb716 100644 --- a/MANIFEST +++ b/MANIFEST @@ -2177,6 +2177,7 @@ lib/vars_carp.t See if "use vars" doesn't load Carp.pm per default lib/vars.pm Declare pseudo-imported global variables lib/vars.t See if "use vars" works lib/version.pm Support for version objects +lib/version.pod Documentation of the version module lib/version.t Tests for version objects lib/vmsish.pm Control VMS-specific behavior of Perl core lib/vmsish.t Tests for vmsish.pm diff --git a/lib/version.pm b/lib/version.pm index 1e3cabb..56efdaf 100644 --- a/lib/version.pm +++ b/lib/version.pm @@ -5,571 +5,16 @@ use 5.005_03; use strict; require Exporter; -require DynaLoader; use vars qw(@ISA $VERSION $CLASS @EXPORT); -@ISA = qw(Exporter DynaLoader); +@ISA = qw(Exporter); @EXPORT = qw(qv); -$VERSION = "0.47"; +$VERSION = "0.48"; $CLASS = 'version'; -local $^W; # shut up the 'redefined' warning for UNIVERSAL::VERSION -bootstrap version if $] < 5.009; - # Preloaded methods go here. 1; -__END__ - -=head1 NAME - -version - Perl extension for Version Objects - -=head1 SYNOPSIS - - use version; - $version = version->new("12.2.1"); # must be quoted for Perl < 5.8.1 - print $version; # 12.2.1 - print $version->numify; # 12.002001 - if ( $version gt "12.2" ) # true - - $alphaver = version->new("1.02_03"); # must be quoted! - print $alphaver; # 1.02_030 - print $alphaver->is_alpha(); # true - - $ver = qv(1.2); # 1.2.0 - $ver = qv("1.2"); # 1.2.0 - - $perlver = version->new(5.005_03); # must not be quoted! - print $perlver; # 5.005030 - -=head1 DESCRIPTION - -Overloaded version objects for all versions of Perl. This module -implements all of the features of version objects which will be part -of Perl 5.10.0 except automatic version object creation. - -=head2 What IS a version - -For the purposes of this module, a version "number" is a sequence of -positive integral values separated by decimal points and optionally a -single underscore. This corresponds to what Perl itself uses for a -version, as well as extending the "version as number" that is discussed -in the various editions of the Camel book. - -There are actually two distinct ways to initialize versions: - -=over 4 - -=item * Numeric Versions - -Any initial parameter which "looks like a number", see L. This also covers versions with a single decimal place and -a single embedded underscore, see L, even though -these must be quoted to preserve the underscore formatting. - -=item * Quoted Versions - -Any initial parameter which contains more than one decimal point -and an optional embedded underscore, see L. - -=back - -Both of these methods will produce similar version objects, in that -the default stringification will yield the version L only -if required: - - $v = version->new(1.002); # 1.002, but compares like 1.2.0 - $v = version->new(1.002003); # 1.002003 - $v2 = version->new( "1.2.3"); # v1.2.3 - $v3 = version->new( 1.2.3); # v1.2.3 for Perl >= 5.8.1 - -In specific, version numbers initialized as L will -stringify in Numeric form. Version numbers initialized as L -will be stringified as L. - -Please see L for more details on how Perl will parse various -input values. - -Any value passed to the new() operator will be parsed only so far as it -contains a numeric, decimal, or underscore character. So, for example: - - $v1 = version->new("99 and 94/100 percent pure"); # $v1 == 99.0 - $v2 = version->new("something"); # $v2 == "" and $v2->numify == 0 - -However, see L for one case where non-numeric text is -acceptable when initializing version objects. - -=head2 What about v-strings? - -Beginning with Perl 5.6.0, an alternate method to code arbitrary strings -of bytes was introduced, called v-strings. They were intended to be an -easy way to enter, for example, Unicode strings (which contain two bytes -per character). Some programs have used them to encode printer control -characters (e.g. CRLF). They were also intended to be used for $VERSION. -Their use has been problematic from the start and they will be phased out -beginning in Perl 5.10.0. - -There are two ways to enter v-strings: a bare number with two or more -decimal places, or a bare number with one or more decimal places and a -leading 'v' character (also bare). For example: - - $vs1 = 1.2.3; # encoded as \1\2\3 - $vs2 = v1.2; # encoded as \1\2 - -The first of those two syntaxes is destined to be the default way to create -a version object in 5.10.0, whereas the second will issue a mandatory -deprecation warning beginning at the same time. In both cases, a v-string -encoded version will always be stringified in the version L. - -Consequently, the use of v-strings to initialize version objects with -this module is only possible with Perl 5.8.1 or better (which contain special -code to enable it). Their use is B discouraged in all -circumstances (especially the leading 'v' style), since the meaning will -change depending on which Perl you are running. It is better to use -L<"Quoted Versions"> to ensure the proper interpretation. - -=head2 Numeric Versions - -These correspond to historical versions of Perl itself prior to 5.6.0, -as well as all other modules which follow the Camel rules for the -$VERSION scalar. A numeric version is initialized with what looks like -a floating point number. Leading zeros B significant and trailing -zeros are implied so that a minimum of three places is maintained -between subversions. What this means is that any subversion (digits -to the right of the decimal place) that contains less than three digits -will have trailing zeros added to make up the difference, but only for -purposes of comparison with other version objects. For example: - - $v = version->new( 1.2); # prints 1.2, compares as 1.200.0 - $v = version->new( 1.02); # prints 1.02, compares as 1.20.0 - $v = version->new( 1.002); # prints 1.002, compares as 1.2.0 - $v = version->new( 1.0023); # 1.2.300 - $v = version->new( 1.00203); # 1.2.30 - $v = version->new( 1.002_03); # 1.2.30 See "Quoting" - $v = version->new( 1.002003); # 1.2.3 - -All of the preceding examples except the second to last are true -whether or not the input value is quoted. The important feature is that -the input value contains only a single decimal. - -IMPORTANT NOTE: If your numeric version contains more than 3 significant -digits after the decimal place, it will be split on each multiple of 3, so -1.0003 becomes 1.0.300, due to the need to remain compatible with Perl's -own 5.005_03 == 5.5.30 interpretation. - -=head2 Quoted Versions - -These are the newest form of versions, and correspond to Perl's own -version style beginning with 5.6.0. Starting with Perl 5.10.0, -and most likely Perl 6, this is likely to be the preferred form. This -method requires that the input parameter be quoted, although Perl's after -5.9.0 can use bare numbers with multiple decimal places as a special form -of quoting. - -Unlike L, Quoted Versions may have more than -a single decimal point, e.g. "5.6.1" (for all versions of Perl). If a -Quoted Version has only one decimal place (and no embedded underscore), -it is interpreted exactly like a L. - -So, for example: - - $v = version->new( "1.002"); # 1.2 - $v = version->new( "1.2.3"); # 1.2.3 - $v = version->new("1.0003"); # 1.0.300 - -In addition to conventional versions, Quoted Versions can be -used to create L. - -In general, Quoted Versions permit the greatest amount of freedom -to specify a version, whereas Numeric Versions enforce a certain -uniformity. See also L for an additional method of -initializing version objects. - -=head2 Numeric Alpha Versions - -The one time that a numeric version must be quoted is when a alpha form is -used with an otherwise numeric version (i.e. a single decimal place). This -is commonly used for CPAN releases, where CPAN or CPANPLUS will ignore alpha -versions for automatic updating purposes. Since some developers have used -only two significant decimal places for their non-alpha releases, the -version object will automatically take that into account if the initializer -is quoted. For example Module::Example was released to CPAN with the -following sequence of $VERSION's: - - # $VERSION Stringified - 0.01 0.010 - 0.02 0.020 - 0.02_01 0.02_0100 - 0.02_02 0.02_0200 - 0.03 0.030 - etc. - -As you can see, the version object created from the values in the first -column may contain a trailing 0, but will otherwise be both mathematically -equivalent and sorts alpha-numerically as would be expected. - -=head2 Object Methods - -Overloading has been used with version objects to provide a natural -interface for their use. All mathematical operations are forbidden, -since they don't make any sense for base version objects. - -=over 4 - -=item * New Operator - -Like all OO interfaces, the new() operator is used to initialize -version objects. One way to increment versions when programming is to -use the CVS variable $Revision, which is automatically incremented by -CVS every time the file is committed to the repository. - -In order to facilitate this feature, the following -code can be employed: - - $VERSION = version->new(qw$Revision: 2.7 $); - -and the version object will be created as if the following code -were used: - - $VERSION = version->new("v2.7"); - -In other words, the version will be automatically parsed out of the -string, and it will be quoted to preserve the meaning CVS normally -carries for versions. The CVS $Revision$ increments differently from -numeric versions (i.e. 1.10 follows 1.9), so it must be handled as if -it were a L. - -A new version object can be created as a copy of an existing version -object, either as a class method: - - $v1 = version->new(12.3); - $v2 = version->new($v1); - -or as an object method: - - $v1 = version->new(12.3); - $v2 = $v1->new(); - -and in each case, $v1 and $v2 will be identical. - -=back - -=over 4 - -=item * qv() - -An alternate way to create a new version object is through the exported -qv() sub. This is not strictly like other q? operators (like qq, qw), -in that the only delimiters supported are parentheses (or spaces). It is -the best way to initialize a short version without triggering the floating -point interpretation. For example: - - $v1 = qv(1.2); # 1.2.0 - $v2 = qv("1.2"); # also 1.2.0 - -As you can see, either a bare number or a quoted string can be used, and -either will yield the same version number. - -=back - -For the subsequent examples, the following three objects will be used: - - $ver = version->new("1.2.3.4"); # see "Quoting" below - $alpha = version->new("1.2.3_4"); # see "Alpha versions" below - $nver = version->new(1.002); # see "Numeric Versions" above - -=over 4 - -=item * Normal Form - -For any version object which is initialized with multiple decimal -places (either quoted or if possible v-string), or initialized using -the L operator, the stringified representation is returned in -a normalized or reduced form (no extraneous zeros), and with a leading 'v': - - print $ver->normal; # prints as v1.2.3 - print $ver->stringify; # ditto - print $ver; # ditto - print $nver->normal; # prints as v1.2.0 - print $nver->stringify; # prints as 1.002, see "Stringification" - -In order to preserve the meaning of the processed version, the -normalized representation will always contain at least three sub terms. -In other words, the following is guaranteed to always be true: - - my $newver = version->new($ver->stringify); - if ($newver eq $ver ) # always true - {...} - -=back - -=over 4 - -=item * Numification - -Although all mathematical operations on version objects are forbidden -by default, it is possible to retrieve a number which roughly -corresponds to the version object through the use of the $obj->numify -method. For formatting purposes, when displaying a number which -corresponds a version object, all sub versions are assumed to have -three decimal places. So for example: - - print $ver->numify; # prints 1.002003 - print $nver->numify; # prints 1.002 - -Unlike the stringification operator, there is never any need to append -trailing zeros to preserve the correct version value. - -=back - -=over 4 - -=item * Stringification - -In order to mirror as much as possible the existing behavior of ordinary -$VERSION scalars, the stringification operation will display differently, -depending on whether the version was initialized as a L -or L. - -What this means in practice is that if the normal CPAN and Camel rules are -followed ($VERSION is a floating point number with no more than 3 decimal -places), the stringified output will be exactly the same as the numified -output. There will be no visible difference, although the internal -representation will be different, and the L will -function using the internal coding. - -If a version object is initialized using a L form, or if -the number of significant decimal places exceed three, then the stringified -form will be the L. The $obj->normal operation can always be -used to produce the L, even if the version was originally a -L. - - print $ver->stringify; # prints v1.2.3 - print $nver->stringify; # prints 1.002 - -=back - -=over 4 - -=item * Comparison operators - -Both cmp and <=> operators perform the same comparison between terms -(upgrading to a version object automatically). Perl automatically -generates all of the other comparison operators based on those two. -In addition to the obvious equalities listed below, appending a single -trailing 0 term does not change the value of a version for comparison -purposes. In other words "v1.2" and "1.2.0" will compare as identical. - -For example, the following relations hold: - - As Number As String Truth Value - --------- ------------ ----------- - $ver > 1.0 $ver gt "1.0" true - $ver < 2.5 $ver lt true - $ver != 1.3 $ver ne "1.3" true - $ver == 1.2 $ver eq "1.2" false - $ver == 1.2.3 $ver eq "1.2.3" see discussion below - -It is probably best to chose either the numeric notation or the string -notation and stick with it, to reduce confusion. Perl6 version objects -B only support numeric comparisons. See also L<"Quoting">. - -WARNING: Comparing version with unequal numbers of decimal places (whether -explicitly or implicitly initialized), may yield unexpected results at -first glance. For example, the following inequalities hold: - - version->new(0.96) > version->new(0.95); # 0.960.0 > 0.950.0 - version->new("0.96.1") < version->new(0.95); # 0.096.1 < 0.950.0 - -For this reason, it is best to use either exclusively L or -L with multiple decimal places. - -=back - -=over 4 - -=item * Logical Operators - -If you need to test whether a version object -has been initialized, you can simply test it directly: - - $vobj = version->new($something); - if ( $vobj ) # true only if $something was non-blank - -You can also test whether a version object is an L, for -example to prevent the use of some feature not present in the main -release: - - $vobj = version->new("1.2_3"); # MUST QUOTE - ...later... - if ( $vobj->is_alpha ) # True - -=back - -=head2 Quoting - -Because of the nature of the Perl parsing and tokenizing routines, -certain initialization values B be quoted in order to correctly -parse as the intended version, and additionally, some initial values -B be quoted to obtain the intended version. - -Except for L, any version initialized with something -that looks like a number (a single decimal place) will be parsed in -the same way whether or not the term is quoted. In order to be -compatible with earlier Perl version styles, any use of versions of -the form 5.006001 will be translated as 5.6.1. In other words, a -version with a single decimal place will be parsed as implicitly -having three places between subversions. - -The complicating factor is that in bare numbers (i.e. unquoted), the -underscore is a legal numeric character and is automatically stripped -by the Perl tokenizer before the version code is called. However, if -a number containing one or more decimals and an underscore is quoted, i.e. -not bare, that is considered a L and the underscore is -significant. - -If you use a mathematic formula that resolves to a floating point number, -you are dependent on Perl's conversion routines to yield the version you -expect. You are pretty safe by dividing by a power of 10, for example, -but other operations are not likely to be what you intend. For example: - - $VERSION = version->new((qw$Revision: 1.4)[1]/10); - print $VERSION; # yields 0.14 - $V2 = version->new(100/9); # Integer overflow in decimal number - print $V2; # yields something like 11.111.111.100 - -Perl 5.8.1 and beyond will be able to automatically quote v-strings but -that is not possible in earlier versions of Perl. In other words: - - $version = version->new("v2.5.4"); # legal in all versions of Perl - $newvers = version->new(v2.5.4); # legal only in Perl >= 5.8.1 - - -=head2 Types of Versions Objects - -There are two types of Version Objects: - -=over 4 - -=item * Ordinary versions - -These are the versions that normal modules will use. Can contain as -many subversions as required. In particular, those using RCS/CVS can -use the following: - - $VERSION = version->new(qw$Revision: 2.7 $); - -and the current RCS Revision for that file will be inserted -automatically. If the file has been moved to a branch, the Revision -will have three or more elements; otherwise, it will have only two. -This allows you to automatically increment your module version by -using the Revision number from the primary file in a distribution, see -L. - -=item * Alpha Versions - -For module authors using CPAN, the convention has been to note -unstable releases with an underscore in the version string, see -L. Alpha releases will test as being newer than the more recent -stable release, and less than the next stable release. For example: - - $alphaver = version->new("12.03_01"); # must be quoted - -obeys the relationship - - 12.03 < $alphaver < 12.04 - -Alpha versions with a single decimal place will be treated exactly as if -they were L, for parsing purposes. The stringification for -alpha versions with a single decimal place may seem surprising, since any -trailing zeros will visible. For example, the above $alphaver will print as - - 12.03_0100 - -which is mathematically equivalent and ASCII sorts exactly the same as -without the trailing zeros. - -Alpha versions with more than a single decimal place will be treated -exactly as if they were L, and will display without any -trailing (or leading) zeros, in the L form. For example, - - $newver = version->new("12.3.1_1"); - print $newver; # v12.3.1_1 - -=head2 Replacement UNIVERSAL::VERSION - -In addition to the version objects, this modules also replaces the core -UNIVERSAL::VERSION function with one that uses version objects for its -comparisons. The return from this operator is always the numified form, -and the warning message generated includes both the numified and normal -forms (for clarity). - -For example: - - package Foo; - $VERSION = 1.2; - - package Bar; - $VERSION = "1.3.5"; # works with all Perl's (since it is quoted) - - package main; - use version; - - print $Foo::VERSION; # prints 1.2 - - print $Bar::VERSION; # prints 1.003005 - - eval "use CGI 10"; # some far future release - print $@; # prints "CGI version 10 (10.0.0) required..." - -IMPORTANT NOTE: This may mean that code which searches for a specific -string (to determine whether a given module is available) may need to be -changed. - -The replacement UNIVERSAL::VERSION, when used as a function, like this: - - print $module->VERSION; - -will also exclusively return the numified form. Technically, the -$module->VERSION function returns a string (PV) that can be converted to a -number following the normal Perl rules, when used in a numeric context. - -=head1 SUBCLASSING - -This module is specifically designed and tested to be easily subclassed. -In practice, you only need to override the methods you want to change, but -you have to take some care when overriding new() (since that is where all -of the parsing takes place). For example, this is a perfect acceptable -derived class: - - package myversion; - use base version; - sub new { - my($self,$n)=@_; - my $obj; - # perform any special input handling here - $obj = $self->SUPER::new($n); - # and/or add additional hash elements here - return $obj; - } - -See also L on CPAN for an alternate representation of -version strings. - -=head1 EXPORT - -qv - quoted version initialization operator - -=head1 AUTHOR - -John Peacock Ejpeacock@cpan.orgE - -=head1 SEE ALSO - -L. - -=cut diff --git a/lib/version.pod b/lib/version.pod new file mode 100644 index 0000000..eb9a301 --- /dev/null +++ b/lib/version.pod @@ -0,0 +1,1098 @@ +=head1 NAME + +version - Perl extension for Version Objects + +=head1 SYNOPSIS + + use version; + $version = version->new("12.2.1"); # must be quoted for Perl < 5.8.1 + print $version; # 12.2.1 + print $version->numify; # 12.002001 + if ( $version gt "12.2" ) # true + + $alphaver = version->new("1.02_03"); # must be quoted! + print $alphaver; # 1.02_030 + print $alphaver->is_alpha(); # true + + $ver = qv(1.2); # 1.2.0 + $ver = qv("1.2"); # 1.2.0 + + $perlver = version->new(5.005_03); # must not be quoted! + print $perlver; # 5.005030 + +=head1 DESCRIPTION + +Overloaded version objects for all versions of Perl. This module +implements all of the features of version objects which will be part +of Perl 5.10.0 except automatic version object creation. + +=head2 What IS a version + +For the purposes of this module, a version "number" is a sequence of +positive integral values separated by decimal points and optionally a +single underscore. This corresponds to what Perl itself uses for a +version, as well as extending the "version as number" that is discussed +in the various editions of the Camel book. + +There are actually two distinct ways to initialize versions: + +=over 4 + +=item * Numeric Versions + +Any initial parameter which "looks like a number", see L. This also covers versions with a single decimal place and +a single embedded underscore, see L, even though +these must be quoted to preserve the underscore formatting. + +=item * Quoted Versions + +Any initial parameter which contains more than one decimal point +and an optional embedded underscore, see L. + +=back + +Both of these methods will produce similar version objects, in that +the default stringification will yield the version L only +if required: + + $v = version->new(1.002); # 1.002, but compares like 1.2.0 + $v = version->new(1.002003); # 1.002003 + $v2 = version->new( "1.2.3"); # v1.2.3 + $v3 = version->new( 1.2.3); # v1.2.3 for Perl >= 5.8.1 + +In specific, version numbers initialized as L will +stringify in Numeric form. Version numbers initialized as L +will be stringified as L. + +Please see L for more details on how Perl will parse various +input values. + +Any value passed to the new() operator will be parsed only so far as it +contains a numeric, decimal, or underscore character. So, for example: + + $v1 = version->new("99 and 94/100 percent pure"); # $v1 == 99.0 + $v2 = version->new("something"); # $v2 == "" and $v2->numify == 0 + +However, see L for one case where non-numeric text is +acceptable when initializing version objects. + +=head2 What about v-strings? + +Beginning with Perl 5.6.0, an alternate method to code arbitrary strings +of bytes was introduced, called v-strings. They were intended to be an +easy way to enter, for example, Unicode strings (which contain two bytes +per character). Some programs have used them to encode printer control +characters (e.g. CRLF). They were also intended to be used for $VERSION. +Their use has been problematic from the start and they will be phased out +beginning in Perl 5.10.0. + +There are two ways to enter v-strings: a bare number with two or more +decimal places, or a bare number with one or more decimal places and a +leading 'v' character (also bare). For example: + + $vs1 = 1.2.3; # encoded as \1\2\3 + $vs2 = v1.2; # encoded as \1\2 + +The first of those two syntaxes is destined to be the default way to create +a version object in 5.10.0, whereas the second will issue a mandatory +deprecation warning beginning at the same time. In both cases, a v-string +encoded version will always be stringified in the version L. + +Consequently, the use of v-strings to initialize version objects with +this module is only possible with Perl 5.8.1 or better (which contain special +code to enable it). Their use is B discouraged in all +circumstances (especially the leading 'v' style), since the meaning will +change depending on which Perl you are running. It is better to use +L<"Quoted Versions"> to ensure the proper interpretation. + +=head2 Numeric Versions + +These correspond to historical versions of Perl itself prior to 5.6.0, +as well as all other modules which follow the Camel rules for the +$VERSION scalar. A numeric version is initialized with what looks like +a floating point number. Leading zeros B significant and trailing +zeros are implied so that a minimum of three places is maintained +between subversions. What this means is that any subversion (digits +to the right of the decimal place) that contains less than three digits +will have trailing zeros added to make up the difference, but only for +purposes of comparison with other version objects. For example: + + $v = version->new( 1.2); # prints 1.2, compares as 1.200.0 + $v = version->new( 1.02); # prints 1.02, compares as 1.20.0 + $v = version->new( 1.002); # prints 1.002, compares as 1.2.0 + $v = version->new( 1.0023); # 1.2.300 + $v = version->new( 1.00203); # 1.2.30 + $v = version->new( 1.002_03); # 1.2.30 See "Quoting" + $v = version->new( 1.002003); # 1.2.3 + +All of the preceding examples except the second to last are true +whether or not the input value is quoted. The important feature is that +the input value contains only a single decimal. + +IMPORTANT NOTE: If your numeric version contains more than 3 significant +digits after the decimal place, it will be split on each multiple of 3, so +1.0003 becomes 1.0.300, due to the need to remain compatible with Perl's +own 5.005_03 == 5.5.30 interpretation. + +=head2 Quoted Versions + +These are the newest form of versions, and correspond to Perl's own +version style beginning with 5.6.0. Starting with Perl 5.10.0, +and most likely Perl 6, this is likely to be the preferred form. This +method requires that the input parameter be quoted, although Perl's after +5.9.0 can use bare numbers with multiple decimal places as a special form +of quoting. + +Unlike L, Quoted Versions may have more than +a single decimal point, e.g. "5.6.1" (for all versions of Perl). If a +Quoted Version has only one decimal place (and no embedded underscore), +it is interpreted exactly like a L. + +So, for example: + + $v = version->new( "1.002"); # 1.2 + $v = version->new( "1.2.3"); # 1.2.3 + $v = version->new("1.0003"); # 1.0.300 + +In addition to conventional versions, Quoted Versions can be +used to create L. + +In general, Quoted Versions permit the greatest amount of freedom +to specify a version, whereas Numeric Versions enforce a certain +uniformity. See also L for an additional method of +initializing version objects. + +=head2 Numeric Alpha Versions + +The one time that a numeric version must be quoted is when a alpha form is +used with an otherwise numeric version (i.e. a single decimal place). This +is commonly used for CPAN releases, where CPAN or CPANPLUS will ignore alpha +versions for automatic updating purposes. Since some developers have used +only two significant decimal places for their non-alpha releases, the +version object will automatically take that into account if the initializer +is quoted. For example Module::Example was released to CPAN with the +following sequence of $VERSION's: + + # $VERSION Stringified + 0.01 0.010 + 0.02 0.020 + 0.02_01 0.02_0100 + 0.02_02 0.02_0200 + 0.03 0.030 + etc. + +As you can see, the version object created from the values in the first +column may contain a trailing 0, but will otherwise be both mathematically +equivalent and sorts alpha-numerically as would be expected. + +=head2 Object Methods + +Overloading has been used with version objects to provide a natural +interface for their use. All mathematical operations are forbidden, +since they don't make any sense for base version objects. + +=over 4 + +=item * New Operator + +Like all OO interfaces, the new() operator is used to initialize +version objects. One way to increment versions when programming is to +use the CVS variable $Revision, which is automatically incremented by +CVS every time the file is committed to the repository. + +In order to facilitate this feature, the following +code can be employed: + + $VERSION = version->new(qw$Revision: 2.7 $); + +and the version object will be created as if the following code +were used: + + $VERSION = version->new("v2.7"); + +In other words, the version will be automatically parsed out of the +string, and it will be quoted to preserve the meaning CVS normally +carries for versions. The CVS $Revision$ increments differently from +numeric versions (i.e. 1.10 follows 1.9), so it must be handled as if +it were a L. + +A new version object can be created as a copy of an existing version +object, either as a class method: + + $v1 = version->new(12.3); + $v2 = version->new($v1); + +or as an object method: + + $v1 = version->new(12.3); + $v2 = $v1->new(); + +and in each case, $v1 and $v2 will be identical. + +=back + +=over 4 + +=item * qv() + +An alternate way to create a new version object is through the exported +qv() sub. This is not strictly like other q? operators (like qq, qw), +in that the only delimiters supported are parentheses (or spaces). It is +the best way to initialize a short version without triggering the floating +point interpretation. For example: + + $v1 = qv(1.2); # 1.2.0 + $v2 = qv("1.2"); # also 1.2.0 + +As you can see, either a bare number or a quoted string can be used, and +either will yield the same version number. + +=back + +For the subsequent examples, the following three objects will be used: + + $ver = version->new("1.2.3.4"); # see "Quoting" below + $alpha = version->new("1.2.3_4"); # see "Alpha versions" below + $nver = version->new(1.002); # see "Numeric Versions" above + +=over 4 + +=item * Normal Form + +For any version object which is initialized with multiple decimal +places (either quoted or if possible v-string), or initialized using +the L operator, the stringified representation is returned in +a normalized or reduced form (no extraneous zeros), and with a leading 'v': + + print $ver->normal; # prints as v1.2.3 + print $ver->stringify; # ditto + print $ver; # ditto + print $nver->normal; # prints as v1.2.0 + print $nver->stringify; # prints as 1.002, see "Stringification" + +In order to preserve the meaning of the processed version, the +normalized representation will always contain at least three sub terms. +In other words, the following is guaranteed to always be true: + + my $newver = version->new($ver->stringify); + if ($newver eq $ver ) # always true + {...} + +=back + +=over 4 + +=item * Numification + +Although all mathematical operations on version objects are forbidden +by default, it is possible to retrieve a number which roughly +corresponds to the version object through the use of the $obj->numify +method. For formatting purposes, when displaying a number which +corresponds a version object, all sub versions are assumed to have +three decimal places. So for example: + + print $ver->numify; # prints 1.002003 + print $nver->numify; # prints 1.002 + +Unlike the stringification operator, there is never any need to append +trailing zeros to preserve the correct version value. + +=back + +=over 4 + +=item * Stringification + +In order to mirror as much as possible the existing behavior of ordinary +$VERSION scalars, the stringification operation will display differently, +depending on whether the version was initialized as a L +or L. + +What this means in practice is that if the normal CPAN and Camel rules are +followed ($VERSION is a floating point number with no more than 3 decimal +places), the stringified output will be exactly the same as the numified +output. There will be no visible difference, although the internal +representation will be different, and the L will +function using the internal coding. + +If a version object is initialized using a L form, or if +the number of significant decimal places exceed three, then the stringified +form will be the L. The $obj->normal operation can always be +used to produce the L, even if the version was originally a +L. + + print $ver->stringify; # prints v1.2.3 + print $nver->stringify; # prints 1.002 + +=back + +=over 4 + +=item * Comparison operators + +Both cmp and <=> operators perform the same comparison between terms +(upgrading to a version object automatically). Perl automatically +generates all of the other comparison operators based on those two. +In addition to the obvious equalities listed below, appending a single +trailing 0 term does not change the value of a version for comparison +purposes. In other words "v1.2" and "1.2.0" will compare as identical. + +For example, the following relations hold: + + As Number As String Truth Value + --------- ------------ ----------- + $ver > 1.0 $ver gt "1.0" true + $ver < 2.5 $ver lt true + $ver != 1.3 $ver ne "1.3" true + $ver == 1.2 $ver eq "1.2" false + $ver == 1.2.3 $ver eq "1.2.3" see discussion below + +It is probably best to chose either the numeric notation or the string +notation and stick with it, to reduce confusion. Perl6 version objects +B only support numeric comparisons. See also L<"Quoting">. + +WARNING: Comparing version with unequal numbers of decimal places (whether +explicitly or implicitly initialized), may yield unexpected results at +first glance. For example, the following inequalities hold: + + version->new(0.96) > version->new(0.95); # 0.960.0 > 0.950.0 + version->new("0.96.1") < version->new(0.95); # 0.096.1 < 0.950.0 + +For this reason, it is best to use either exclusively L or +L with multiple decimal places. + +=back + +=over 4 + +=item * Logical Operators + +If you need to test whether a version object +has been initialized, you can simply test it directly: + + $vobj = version->new($something); + if ( $vobj ) # true only if $something was non-blank + +You can also test whether a version object is an L, for +example to prevent the use of some feature not present in the main +release: + + $vobj = version->new("1.2_3"); # MUST QUOTE + ...later... + if ( $vobj->is_alpha ) # True + +=back + +=head2 Quoting + +Because of the nature of the Perl parsing and tokenizing routines, +certain initialization values B be quoted in order to correctly +parse as the intended version, and additionally, some initial values +B be quoted to obtain the intended version. + +Except for L, any version initialized with something +that looks like a number (a single decimal place) will be parsed in +the same way whether or not the term is quoted. In order to be +compatible with earlier Perl version styles, any use of versions of +the form 5.006001 will be translated as 5.6.1. In other words, a +version with a single decimal place will be parsed as implicitly +having three places between subversions. + +The complicating factor is that in bare numbers (i.e. unquoted), the +underscore is a legal numeric character and is automatically stripped +by the Perl tokenizer before the version code is called. However, if +a number containing one or more decimals and an underscore is quoted, i.e. +not bare, that is considered a L and the underscore is +significant. + +If you use a mathematic formula that resolves to a floating point number, +you are dependent on Perl's conversion routines to yield the version you +expect. You are pretty safe by dividing by a power of 10, for example, +but other operations are not likely to be what you intend. For example: + + $VERSION = version->new((qw$Revision: 1.4)[1]/10); + print $VERSION; # yields 0.14 + $V2 = version->new(100/9); # Integer overflow in decimal number + print $V2; # yields something like 11.111.111.100 + +Perl 5.8.1 and beyond will be able to automatically quote v-strings but +that is not possible in earlier versions of Perl. In other words: + + $version = version->new("v2.5.4"); # legal in all versions of Perl + $newvers = version->new(v2.5.4); # legal only in Perl >= 5.8.1 + + +=head2 Types of Versions Objects + +There are two types of Version Objects: + +=over 4 + +=item * Ordinary versions + +These are the versions that normal modules will use. Can contain as +many subversions as required. In particular, those using RCS/CVS can +use the following: + + $VERSION = version->new(qw$Revision: 2.7 $); + +and the current RCS Revision for that file will be inserted +automatically. If the file has been moved to a branch, the Revision +will have three or more elements; otherwise, it will have only two. +This allows you to automatically increment your module version by +using the Revision number from the primary file in a distribution, see +L. + +=item * Alpha Versions + +For module authors using CPAN, the convention has been to note +unstable releases with an underscore in the version string, see +L. Alpha releases will test as being newer than the more recent +stable release, and less than the next stable release. For example: + + $alphaver = version->new("12.03_01"); # must be quoted + +obeys the relationship + + 12.03 < $alphaver < 12.04 + +Alpha versions with a single decimal place will be treated exactly as if +they were L, for parsing purposes. The stringification for +alpha versions with a single decimal place may seem surprising, since any +trailing zeros will visible. For example, the above $alphaver will print as + + 12.03_0100 + +which is mathematically equivalent and ASCII sorts exactly the same as +without the trailing zeros. + +Alpha versions with more than a single decimal place will be treated +exactly as if they were L, and will display without any +trailing (or leading) zeros, in the L form. For example, + + $newver = version->new("12.3.1_1"); + print $newver; # v12.3.1_1 + +=head2 Replacement UNIVERSAL::VERSION + +In addition to the version objects, this modules also replaces the core +UNIVERSAL::VERSION function with one that uses version objects for its +comparisons. The return from this operator is always the numified form, +and the warning message generated includes both the numified and normal +forms (for clarity). + +For example: + + package Foo; + $VERSION = 1.2; + + package Bar; + $VERSION = "1.3.5"; # works with all Perl's (since it is quoted) + + package main; + use version; + + print $Foo::VERSION; # prints 1.2 + + print $Bar::VERSION; # prints 1.003005 + + eval "use CGI 10"; # some far future release + print $@; # prints "CGI version 10 (10.0.0) required..." + +IMPORTANT NOTE: This may mean that code which searches for a specific +string (to determine whether a given module is available) may need to be +changed. + +The replacement UNIVERSAL::VERSION, when used as a function, like this: + + print $module->VERSION; + +will also exclusively return the numified form. Technically, the +$module->VERSION function returns a string (PV) that can be converted to a +number following the normal Perl rules, when used in a numeric context. + +=head1 SUBCLASSING + +This module is specifically designed and tested to be easily subclassed. +In practice, you only need to override the methods you want to change, but +you have to take some care when overriding new() (since that is where all +of the parsing takes place). For example, this is a perfect acceptable +derived class: + + package myversion; + use base version; + sub new { + my($self,$n)=@_; + my $obj; + # perform any special input handling here + $obj = $self->SUPER::new($n); + # and/or add additional hash elements here + return $obj; + } + +See also L on CPAN for an alternate representation of +version strings. + +=head1 EXPORT + +qv - quoted version initialization operator + +=head1 AUTHOR + +John Peacock Ejpeacock@cpan.orgE + +=head1 SEE ALSO + +L. + +=cut +=head1 NAME + +version - Perl extension for Version Objects + +=head1 SYNOPSIS + + use version; + $version = version->new("12.2.1"); # must be quoted for Perl < 5.8.1 + print $version; # 12.2.1 + print $version->numify; # 12.002001 + if ( $version gt "12.2" ) # true + + $alphaver = version->new("1.02_03"); # must be quoted! + print $alphaver; # 1.02_030 + print $alphaver->is_alpha(); # true + + $ver = qv(1.2); # 1.2.0 + $ver = qv("1.2"); # 1.2.0 + + $perlver = version->new(5.005_03); # must not be quoted! + print $perlver; # 5.005030 + +=head1 DESCRIPTION + +Overloaded version objects for all versions of Perl. This module +implements all of the features of version objects which will be part +of Perl 5.10.0 except automatic version object creation. + +=head2 What IS a version + +For the purposes of this module, a version "number" is a sequence of +positive integral values separated by decimal points and optionally a +single underscore. This corresponds to what Perl itself uses for a +version, as well as extending the "version as number" that is discussed +in the various editions of the Camel book. + +There are actually two distinct ways to initialize versions: + +=over 4 + +=item * Numeric Versions + +Any initial parameter which "looks like a number", see L. This also covers versions with a single decimal place and +a single embedded underscore, see L, even though +these must be quoted to preserve the underscore formatting. + +=item * Quoted Versions + +Any initial parameter which contains more than one decimal point +and an optional embedded underscore, see L. + +=back + +Both of these methods will produce similar version objects, in that +the default stringification will yield the version L only +if required: + + $v = version->new(1.002); # 1.002, but compares like 1.2.0 + $v = version->new(1.002003); # 1.002003 + $v2 = version->new( "1.2.3"); # v1.2.3 + $v3 = version->new( 1.2.3); # v1.2.3 for Perl >= 5.8.1 + +In specific, version numbers initialized as L will +stringify in Numeric form. Version numbers initialized as L +will be stringified as L. + +Please see L for more details on how Perl will parse various +input values. + +Any value passed to the new() operator will be parsed only so far as it +contains a numeric, decimal, or underscore character. So, for example: + + $v1 = version->new("99 and 94/100 percent pure"); # $v1 == 99.0 + $v2 = version->new("something"); # $v2 == "" and $v2->numify == 0 + +However, see L for one case where non-numeric text is +acceptable when initializing version objects. + +=head2 What about v-strings? + +Beginning with Perl 5.6.0, an alternate method to code arbitrary strings +of bytes was introduced, called v-strings. They were intended to be an +easy way to enter, for example, Unicode strings (which contain two bytes +per character). Some programs have used them to encode printer control +characters (e.g. CRLF). They were also intended to be used for $VERSION. +Their use has been problematic from the start and they will be phased out +beginning in Perl 5.10.0. + +There are two ways to enter v-strings: a bare number with two or more +decimal places, or a bare number with one or more decimal places and a +leading 'v' character (also bare). For example: + + $vs1 = 1.2.3; # encoded as \1\2\3 + $vs2 = v1.2; # encoded as \1\2 + +The first of those two syntaxes is destined to be the default way to create +a version object in 5.10.0, whereas the second will issue a mandatory +deprecation warning beginning at the same time. In both cases, a v-string +encoded version will always be stringified in the version L. + +Consequently, the use of v-strings to initialize version objects with +this module is only possible with Perl 5.8.1 or better (which contain special +code to enable it). Their use is B discouraged in all +circumstances (especially the leading 'v' style), since the meaning will +change depending on which Perl you are running. It is better to use +L<"Quoted Versions"> to ensure the proper interpretation. + +=head2 Numeric Versions + +These correspond to historical versions of Perl itself prior to 5.6.0, +as well as all other modules which follow the Camel rules for the +$VERSION scalar. A numeric version is initialized with what looks like +a floating point number. Leading zeros B significant and trailing +zeros are implied so that a minimum of three places is maintained +between subversions. What this means is that any subversion (digits +to the right of the decimal place) that contains less than three digits +will have trailing zeros added to make up the difference, but only for +purposes of comparison with other version objects. For example: + + $v = version->new( 1.2); # prints 1.2, compares as 1.200.0 + $v = version->new( 1.02); # prints 1.02, compares as 1.20.0 + $v = version->new( 1.002); # prints 1.002, compares as 1.2.0 + $v = version->new( 1.0023); # 1.2.300 + $v = version->new( 1.00203); # 1.2.30 + $v = version->new( 1.002_03); # 1.2.30 See "Quoting" + $v = version->new( 1.002003); # 1.2.3 + +All of the preceding examples except the second to last are true +whether or not the input value is quoted. The important feature is that +the input value contains only a single decimal. + +IMPORTANT NOTE: If your numeric version contains more than 3 significant +digits after the decimal place, it will be split on each multiple of 3, so +1.0003 becomes 1.0.300, due to the need to remain compatible with Perl's +own 5.005_03 == 5.5.30 interpretation. + +=head2 Quoted Versions + +These are the newest form of versions, and correspond to Perl's own +version style beginning with 5.6.0. Starting with Perl 5.10.0, +and most likely Perl 6, this is likely to be the preferred form. This +method requires that the input parameter be quoted, although Perl's after +5.9.0 can use bare numbers with multiple decimal places as a special form +of quoting. + +Unlike L, Quoted Versions may have more than +a single decimal point, e.g. "5.6.1" (for all versions of Perl). If a +Quoted Version has only one decimal place (and no embedded underscore), +it is interpreted exactly like a L. + +So, for example: + + $v = version->new( "1.002"); # 1.2 + $v = version->new( "1.2.3"); # 1.2.3 + $v = version->new("1.0003"); # 1.0.300 + +In addition to conventional versions, Quoted Versions can be +used to create L. + +In general, Quoted Versions permit the greatest amount of freedom +to specify a version, whereas Numeric Versions enforce a certain +uniformity. See also L for an additional method of +initializing version objects. + +=head2 Numeric Alpha Versions + +The one time that a numeric version must be quoted is when a alpha form is +used with an otherwise numeric version (i.e. a single decimal place). This +is commonly used for CPAN releases, where CPAN or CPANPLUS will ignore alpha +versions for automatic updating purposes. Since some developers have used +only two significant decimal places for their non-alpha releases, the +version object will automatically take that into account if the initializer +is quoted. For example Module::Example was released to CPAN with the +following sequence of $VERSION's: + + # $VERSION Stringified + 0.01 0.010 + 0.02 0.020 + 0.02_01 0.02_0100 + 0.02_02 0.02_0200 + 0.03 0.030 + etc. + +As you can see, the version object created from the values in the first +column may contain a trailing 0, but will otherwise be both mathematically +equivalent and sorts alpha-numerically as would be expected. + +=head2 Object Methods + +Overloading has been used with version objects to provide a natural +interface for their use. All mathematical operations are forbidden, +since they don't make any sense for base version objects. + +=over 4 + +=item * New Operator + +Like all OO interfaces, the new() operator is used to initialize +version objects. One way to increment versions when programming is to +use the CVS variable $Revision, which is automatically incremented by +CVS every time the file is committed to the repository. + +In order to facilitate this feature, the following +code can be employed: + + $VERSION = version->new(qw$Revision: 2.7 $); + +and the version object will be created as if the following code +were used: + + $VERSION = version->new("v2.7"); + +In other words, the version will be automatically parsed out of the +string, and it will be quoted to preserve the meaning CVS normally +carries for versions. The CVS $Revision$ increments differently from +numeric versions (i.e. 1.10 follows 1.9), so it must be handled as if +it were a L. + +A new version object can be created as a copy of an existing version +object, either as a class method: + + $v1 = version->new(12.3); + $v2 = version->new($v1); + +or as an object method: + + $v1 = version->new(12.3); + $v2 = $v1->new(); + +and in each case, $v1 and $v2 will be identical. + +=back + +=over 4 + +=item * qv() + +An alternate way to create a new version object is through the exported +qv() sub. This is not strictly like other q? operators (like qq, qw), +in that the only delimiters supported are parentheses (or spaces). It is +the best way to initialize a short version without triggering the floating +point interpretation. For example: + + $v1 = qv(1.2); # 1.2.0 + $v2 = qv("1.2"); # also 1.2.0 + +As you can see, either a bare number or a quoted string can be used, and +either will yield the same version number. + +=back + +For the subsequent examples, the following three objects will be used: + + $ver = version->new("1.2.3.4"); # see "Quoting" below + $alpha = version->new("1.2.3_4"); # see "Alpha versions" below + $nver = version->new(1.002); # see "Numeric Versions" above + +=over 4 + +=item * Normal Form + +For any version object which is initialized with multiple decimal +places (either quoted or if possible v-string), or initialized using +the L operator, the stringified representation is returned in +a normalized or reduced form (no extraneous zeros), and with a leading 'v': + + print $ver->normal; # prints as v1.2.3 + print $ver->stringify; # ditto + print $ver; # ditto + print $nver->normal; # prints as v1.2.0 + print $nver->stringify; # prints as 1.002, see "Stringification" + +In order to preserve the meaning of the processed version, the +normalized representation will always contain at least three sub terms. +In other words, the following is guaranteed to always be true: + + my $newver = version->new($ver->stringify); + if ($newver eq $ver ) # always true + {...} + +=back + +=over 4 + +=item * Numification + +Although all mathematical operations on version objects are forbidden +by default, it is possible to retrieve a number which roughly +corresponds to the version object through the use of the $obj->numify +method. For formatting purposes, when displaying a number which +corresponds a version object, all sub versions are assumed to have +three decimal places. So for example: + + print $ver->numify; # prints 1.002003 + print $nver->numify; # prints 1.002 + +Unlike the stringification operator, there is never any need to append +trailing zeros to preserve the correct version value. + +=back + +=over 4 + +=item * Stringification + +In order to mirror as much as possible the existing behavior of ordinary +$VERSION scalars, the stringification operation will display differently, +depending on whether the version was initialized as a L +or L. + +What this means in practice is that if the normal CPAN and Camel rules are +followed ($VERSION is a floating point number with no more than 3 decimal +places), the stringified output will be exactly the same as the numified +output. There will be no visible difference, although the internal +representation will be different, and the L will +function using the internal coding. + +If a version object is initialized using a L form, or if +the number of significant decimal places exceed three, then the stringified +form will be the L. The $obj->normal operation can always be +used to produce the L, even if the version was originally a +L. + + print $ver->stringify; # prints v1.2.3 + print $nver->stringify; # prints 1.002 + +=back + +=over 4 + +=item * Comparison operators + +Both cmp and <=> operators perform the same comparison between terms +(upgrading to a version object automatically). Perl automatically +generates all of the other comparison operators based on those two. +In addition to the obvious equalities listed below, appending a single +trailing 0 term does not change the value of a version for comparison +purposes. In other words "v1.2" and "1.2.0" will compare as identical. + +For example, the following relations hold: + + As Number As String Truth Value + --------- ------------ ----------- + $ver > 1.0 $ver gt "1.0" true + $ver < 2.5 $ver lt true + $ver != 1.3 $ver ne "1.3" true + $ver == 1.2 $ver eq "1.2" false + $ver == 1.2.3 $ver eq "1.2.3" see discussion below + +It is probably best to chose either the numeric notation or the string +notation and stick with it, to reduce confusion. Perl6 version objects +B only support numeric comparisons. See also L<"Quoting">. + +WARNING: Comparing version with unequal numbers of decimal places (whether +explicitly or implicitly initialized), may yield unexpected results at +first glance. For example, the following inequalities hold: + + version->new(0.96) > version->new(0.95); # 0.960.0 > 0.950.0 + version->new("0.96.1") < version->new(0.95); # 0.096.1 < 0.950.0 + +For this reason, it is best to use either exclusively L or +L with multiple decimal places. + +=back + +=over 4 + +=item * Logical Operators + +If you need to test whether a version object +has been initialized, you can simply test it directly: + + $vobj = version->new($something); + if ( $vobj ) # true only if $something was non-blank + +You can also test whether a version object is an L, for +example to prevent the use of some feature not present in the main +release: + + $vobj = version->new("1.2_3"); # MUST QUOTE + ...later... + if ( $vobj->is_alpha ) # True + +=back + +=head2 Quoting + +Because of the nature of the Perl parsing and tokenizing routines, +certain initialization values B be quoted in order to correctly +parse as the intended version, and additionally, some initial values +B be quoted to obtain the intended version. + +Except for L, any version initialized with something +that looks like a number (a single decimal place) will be parsed in +the same way whether or not the term is quoted. In order to be +compatible with earlier Perl version styles, any use of versions of +the form 5.006001 will be translated as 5.6.1. In other words, a +version with a single decimal place will be parsed as implicitly +having three places between subversions. + +The complicating factor is that in bare numbers (i.e. unquoted), the +underscore is a legal numeric character and is automatically stripped +by the Perl tokenizer before the version code is called. However, if +a number containing one or more decimals and an underscore is quoted, i.e. +not bare, that is considered a L and the underscore is +significant. + +If you use a mathematic formula that resolves to a floating point number, +you are dependent on Perl's conversion routines to yield the version you +expect. You are pretty safe by dividing by a power of 10, for example, +but other operations are not likely to be what you intend. For example: + + $VERSION = version->new((qw$Revision: 1.4)[1]/10); + print $VERSION; # yields 0.14 + $V2 = version->new(100/9); # Integer overflow in decimal number + print $V2; # yields something like 11.111.111.100 + +Perl 5.8.1 and beyond will be able to automatically quote v-strings but +that is not possible in earlier versions of Perl. In other words: + + $version = version->new("v2.5.4"); # legal in all versions of Perl + $newvers = version->new(v2.5.4); # legal only in Perl >= 5.8.1 + + +=head2 Types of Versions Objects + +There are two types of Version Objects: + +=over 4 + +=item * Ordinary versions + +These are the versions that normal modules will use. Can contain as +many subversions as required. In particular, those using RCS/CVS can +use the following: + + $VERSION = version->new(qw$Revision: 2.7 $); + +and the current RCS Revision for that file will be inserted +automatically. If the file has been moved to a branch, the Revision +will have three or more elements; otherwise, it will have only two. +This allows you to automatically increment your module version by +using the Revision number from the primary file in a distribution, see +L. + +=item * Alpha Versions + +For module authors using CPAN, the convention has been to note +unstable releases with an underscore in the version string, see +L. Alpha releases will test as being newer than the more recent +stable release, and less than the next stable release. For example: + + $alphaver = version->new("12.03_01"); # must be quoted + +obeys the relationship + + 12.03 < $alphaver < 12.04 + +Alpha versions with a single decimal place will be treated exactly as if +they were L, for parsing purposes. The stringification for +alpha versions with a single decimal place may seem surprising, since any +trailing zeros will visible. For example, the above $alphaver will print as + + 12.03_0100 + +which is mathematically equivalent and ASCII sorts exactly the same as +without the trailing zeros. + +Alpha versions with more than a single decimal place will be treated +exactly as if they were L, and will display without any +trailing (or leading) zeros, in the L form. For example, + + $newver = version->new("12.3.1_1"); + print $newver; # v12.3.1_1 + +=head2 Replacement UNIVERSAL::VERSION + +In addition to the version objects, this modules also replaces the core +UNIVERSAL::VERSION function with one that uses version objects for its +comparisons. The return from this operator is always the numified form, +and the warning message generated includes both the numified and normal +forms (for clarity). + +For example: + + package Foo; + $VERSION = 1.2; + + package Bar; + $VERSION = "1.3.5"; # works with all Perl's (since it is quoted) + + package main; + use version; + + print $Foo::VERSION; # prints 1.2 + + print $Bar::VERSION; # prints 1.003005 + + eval "use CGI 10"; # some far future release + print $@; # prints "CGI version 10 (10.0.0) required..." + +IMPORTANT NOTE: This may mean that code which searches for a specific +string (to determine whether a given module is available) may need to be +changed. + +The replacement UNIVERSAL::VERSION, when used as a function, like this: + + print $module->VERSION; + +will also exclusively return the numified form. Technically, the +$module->VERSION function returns a string (PV) that can be converted to a +number following the normal Perl rules, when used in a numeric context. + +=head1 SUBCLASSING + +This module is specifically designed and tested to be easily subclassed. +In practice, you only need to override the methods you want to change, but +you have to take some care when overriding new() (since that is where all +of the parsing takes place). For example, this is a perfect acceptable +derived class: + + package myversion; + use base version; + sub new { + my($self,$n)=@_; + my $obj; + # perform any special input handling here + $obj = $self->SUPER::new($n); + # and/or add additional hash elements here + return $obj; + } + +See also L on CPAN for an alternate representation of +version strings. + +=head1 EXPORT + +qv - quoted version initialization operator + +=head1 AUTHOR + +John Peacock Ejpeacock@cpan.orgE + +=head1 SEE ALSO + +L. + +=cut diff --git a/lib/version.t b/lib/version.t index e387095..c60d656 100644 --- a/lib/version.t +++ b/lib/version.t @@ -18,7 +18,7 @@ diag "Tests with empty derived class" unless $ENV{PERL_CORE}; package version::Empty; use vars qw($VERSION @ISA); -use version 0.30; +use version; @ISA = qw(version); $VERSION = 0.01; @@ -109,7 +109,7 @@ sub BaseTests { ok ($version, 'boolean'); # Test class membership - isa_ok ( $version, "version" ); + isa_ok ( $version, $CLASS ); # Test comparison operators with self diag "tests with self" unless $ENV{PERL_CORE}; @@ -238,7 +238,7 @@ sub BaseTests { # test creation from existing version object diag "create new from existing version" unless $ENV{PERL_CORE}; - ok (eval {$new_version = version->new($version)}, + ok (eval {$new_version = $CLASS->new($version)}, "new from existing object"); ok ($new_version == $version, "class->new($version) identical"); $new_version = $version->new(); @@ -248,9 +248,9 @@ sub BaseTests { # test the CVS revision mode diag "testing CVS Revision" unless $ENV{PERL_CORE}; - $version = new version qw$Revision: 1.2$; + $version = new $CLASS qw$Revision: 1.2$; ok ( $version eq "1.2.0", 'qw$Revision: 1.2$ eq 1.2.0' ); - $version = new version qw$Revision: 1.2.3.4$; + $version = new $CLASS qw$Revision: 1.2.3.4$; ok ( $version eq "1.2.3.4", 'qw$Revision: 1.2.3.4$ eq 1.2.3.4' ); # test the CPAN style reduced significant digit form @@ -320,3 +320,5 @@ SKIP: { ok($version->numify eq "1.700", "leading space ignored"); } + +1; diff --git a/util.c b/util.c index 2f5e2c3..6e39cb6 100644 --- a/util.c +++ b/util.c @@ -3882,11 +3882,12 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) const char *pos; const char *last; int saw_period = 0; - int saw_under = 0; + int alpha = 0; int width = 3; AV *av = newAV(); - SV* hv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */ + SV *hv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */ (void)sv_upgrade(hv, SVt_PVHV); /* needs to be an HV type */ + #ifndef NODEFAULT_SHAREKEYS HvSHAREKEYS_on(hv); /* key-sharing on by default */ #endif @@ -3906,16 +3907,16 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) { if ( *pos == '.' ) { - if ( saw_under ) + if ( alpha ) Perl_croak(aTHX_ "Invalid version format (underscores before decimal)"); saw_period++ ; last = pos; } else if ( *pos == '_' ) { - if ( saw_under ) + if ( alpha ) Perl_croak(aTHX_ "Invalid version format (multiple underscores)"); - saw_under = 1; + alpha = 1; width = pos - last - 1; /* natural width of sub-version */ } pos++; @@ -3927,9 +3928,9 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) pos = s; if ( qv ) - hv_store((HV *)hv, "qv", 2, &PL_sv_yes, 0); - if ( saw_under ) - hv_store((HV *)hv, "alpha", 5, &PL_sv_yes, 0); + hv_store((HV *)hv, "qv", 2, newSViv(qv), 0); + if ( alpha ) + hv_store((HV *)hv, "alpha", 5, newSViv(alpha), 0); if ( !qv && width < 3 ) hv_store((HV *)hv, "width", 5, newSViv(width), 0); @@ -4018,7 +4019,7 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) av_push(av, newSViv(0)); /* And finally, store the AV in the hash */ - hv_store((HV *)hv, "version", 7, (SV *)av, 0); + hv_store((HV *)hv, "version", 7, newRV_noinc((SV *)av), 0); return s; } @@ -4067,7 +4068,7 @@ Perl_new_version(pTHX_ SV *ver) hv_store((HV *)hv, "width", 5, newSViv(width), 0); } - sav = (AV *)*hv_fetch((HV*)ver, "version", 7, FALSE); + sav = (AV *)SvRV(*hv_fetch((HV*)ver, "version", 7, FALSE)); /* This will get reblessed later if a derived class*/ for ( key = 0; key <= av_len(sav); key++ ) { @@ -4075,7 +4076,7 @@ Perl_new_version(pTHX_ SV *ver) av_push(av, newSViv(rev)); } - hv_store((HV *)hv, "version", 7, (SV *)av, 0); + hv_store((HV *)hv, "version", 7, newRV_noinc((SV *)av), 0); return rv; } #ifdef SvVOK @@ -4148,11 +4149,11 @@ confused by derived classes which may contain additional hash entries): =over 4 -=item * The SV contains a hash (or a reference to one) +=item * The SV contains a [reference to a] hash =item * The hash contains a "version" key -=item * The "version" key has an AV as its value +=item * The "version" key has [a reference to] an AV as its value =back @@ -4169,7 +4170,7 @@ Perl_vverify(pTHX_ SV *vs) /* see if the appropriate elements exist */ if ( SvTYPE(vs) == SVt_PVHV && hv_exists((HV*)vs, "version", 7) - && (sv = *hv_fetch((HV*)vs, "version", 7, FALSE)) + && (sv = SvRV(*hv_fetch((HV*)vs, "version", 7, FALSE))) && SvTYPE(sv) == SVt_PVAV ) return TRUE; else @@ -4214,7 +4215,7 @@ Perl_vnumify(pTHX_ SV *vs) /* attempt to retrieve the version array */ - if ( !(av = (AV *)*hv_fetch((HV*)vs, "version", 7, FALSE) ) ) { + if ( !(av = (AV *)SvRV(*hv_fetch((HV*)vs, "version", 7, FALSE)) ) ) { sv_catpvn(sv,"0",1); return sv; } @@ -4284,7 +4285,7 @@ Perl_vnormal(pTHX_ SV *vs) if ( hv_exists((HV*)vs, "alpha", 5 ) ) alpha = TRUE; - av = (AV *)*hv_fetch((HV*)vs, "version", 7, FALSE); + av = (AV *)SvRV(*hv_fetch((HV*)vs, "version", 7, FALSE)); len = av_len(av); if ( len == -1 ) @@ -4294,7 +4295,7 @@ Perl_vnormal(pTHX_ SV *vs) } digit = SvIV(*av_fetch(av, 0, 0)); Perl_sv_setpvf(aTHX_ sv, "v%"IVdf, (IV)digit); - for ( i = 1 ; i <= len-1 ; i++ ) { + for ( i = 1 ; i < len ; i++ ) { digit = SvIV(*av_fetch(av, i, 0)); Perl_sv_catpvf(aTHX_ sv, ".%"IVdf, (IV)digit); } @@ -4330,7 +4331,6 @@ the original version contained 1 or more dots, respectively SV * Perl_vstringify(pTHX_ SV *vs) { - I32 qv = 0; if ( SvROK(vs) ) vs = SvRV(vs); @@ -4338,12 +4338,9 @@ Perl_vstringify(pTHX_ SV *vs) Perl_croak(aTHX_ "Invalid version object"); if ( hv_exists((HV *)vs, "qv", 2) ) - qv = 1; - - if ( qv ) - return Perl_vnormal(aTHX_ vs); + return vnormal(vs); else - return Perl_vnumify(aTHX_ vs); + return vnumify(vs); } /* @@ -4376,12 +4373,12 @@ Perl_vcmp(pTHX_ SV *lhv, SV *rhv) Perl_croak(aTHX_ "Invalid version object"); /* get the left hand term */ - lav = (AV *)*hv_fetch((HV*)lhv, "version", 7, FALSE); + lav = (AV *)SvRV(*hv_fetch((HV*)lhv, "version", 7, FALSE)); if ( hv_exists((HV*)lhv, "alpha", 5 ) ) lalpha = TRUE; /* and the right hand term */ - rav = (AV *)*hv_fetch((HV*)rhv, "version", 7, FALSE); + rav = (AV *)SvRV(*hv_fetch((HV*)rhv, "version", 7, FALSE)); if ( hv_exists((HV*)rhv, "alpha", 5 ) ) ralpha = TRUE;