diff --git a/cpan/version/lib/version.pm b/cpan/version/lib/version.pm index ea47b94eb076..f16f99f2ddb5 100644 --- a/cpan/version/lib/version.pm +++ b/cpan/version/lib/version.pm @@ -8,7 +8,7 @@ if ($] >= 5.015) { warnings::register_categories(qw/version/); } -our $VERSION = '0.9930'; +our $VERSION = '0.9932'; our $CLASS = 'version'; our (@ISA, $STRICT, $LAX); diff --git a/cpan/version/lib/version.pod b/cpan/version/lib/version.pod index 274868508e39..35a5080a6ab4 100644 --- a/cpan/version/lib/version.pod +++ b/cpan/version/lib/version.pod @@ -271,6 +271,30 @@ Returns a value representing the object in a pure decimal. version->declare('v1.2')->numify; # 1.002000 version->parse('1.2')->numify; # 1.200 +=head2 to_decimal + +This returns a new version object for the numified version, much like C<< version->parse($v->numify) >> would. + + version->parse('v1.2')->to_decimal; # 1.002000 + +=head2 to_dotted_decimal + +This returns a new version object for the normalized version, much like C<< version->parse($v->normal) >> would. + + version->parse('1.002')->to_dotted_decimal; # v1.2.0 + +=head2 tuple() + +This turns the components of the version into a list. E.g. + + version->parse('1.2.3')->tuple; # (1, 2, 3) + +=head2 from_tuple(...) + +This takes a list of components and creates a dotted decimal version out of it. E.g. + + version->from_tuple(1, 2, 3) # v1.2.3 + =head2 stringify() Returns a string that is as close to the original representation as possible. @@ -282,6 +306,11 @@ a version object is interpolated into a string. version->parse('1.200')->stringify; # 1.2 version->parse(1.02_30)->stringify; # 1.023 +=head2 tuple + +Returns an array of non-negative integers that is used for comparison purposes with +other version objects. + =head1 EXPORTED FUNCTIONS =head2 qv() diff --git a/cpan/version/lib/version/Internals.pod b/cpan/version/lib/version/Internals.pod index dd784fe4c852..68630a6a9f8d 100644 --- a/cpan/version/lib/version/Internals.pod +++ b/cpan/version/lib/version/Internals.pod @@ -300,58 +300,6 @@ determine whether the v-string encoding was used. form that has a leading 'v' character, for the simple reason that sometimes it is impossible to tell whether one was present initially. -=head2 Version Object Internals - -version.pm provides an overloaded version object that is designed to both -encapsulate the author's intended $VERSION assignment as well as make it -completely natural to use those objects as if they were numbers (e.g. for -comparisons). To do this, a version object contains both the original -representation as typed by the author, as well as a parsed representation -to ease comparisons. Version objects employ L methods to -simplify code that needs to compare, print, etc the objects. - -The internal structure of version objects is a blessed hash with several -components: - - bless( { - 'original' => 'v1.2.3_4', - 'alpha' => 1, - 'qv' => 1, - 'version' => [ - 1, - 2, - 3, - 4 - ] - }, 'version' ); - -=over 4 - -=item original - -A faithful representation of the value used to initialize this version -object. The only time this will not be precisely the same characters -that exist in the source file is if a short dotted-decimal version like -v1.2 was used (in which case it will contain 'v1.2'). This form is -B discouraged, in that it will confuse you and your users. - -=item qv - -A boolean that denotes whether this is a decimal or dotted-decimal version. -See L. - -=item alpha - -A boolean that denotes whether this is an alpha version. NOTE: that the -underscore can only appear in the last position. See L. - -=item version - -An array of non-negative integers that is used for comparison purposes with -other version objects. - -=back - =head2 Replacement UNIVERSAL::VERSION In addition to the version objects, this modules also replaces the core diff --git a/cpan/version/lib/version/regex.pm b/cpan/version/lib/version/regex.pm index 9964b3865364..52ad083a6ecf 100644 --- a/cpan/version/lib/version/regex.pm +++ b/cpan/version/lib/version/regex.pm @@ -2,7 +2,7 @@ package version::regex; use strict; -our $VERSION = '0.9930'; +our $VERSION = '0.9932'; #--------------------------------------------------------------------------# # Version regexp components diff --git a/cpan/version/t/01base.t b/cpan/version/t/01base.t index 68426950332a..a5117f0027de 100644 --- a/cpan/version/t/01base.t +++ b/cpan/version/t/01base.t @@ -14,7 +14,7 @@ BEGIN { ) ); require $coretests; - use_ok('version', 0.9930); + use_ok('version', 0.9932); } BaseTests("version","new","qv"); diff --git a/cpan/version/t/02derived.t b/cpan/version/t/02derived.t index 203fe5f33152..ea471a81e6ce 100644 --- a/cpan/version/t/02derived.t +++ b/cpan/version/t/02derived.t @@ -15,7 +15,7 @@ BEGIN { ) ); require $coretests; - use_ok("version", 0.9930); + use_ok("version", 0.9932); # If we made it this far, we are ok. } diff --git a/cpan/version/t/03require.t b/cpan/version/t/03require.t index 1e421a23883c..57aa8f1fb2a1 100644 --- a/cpan/version/t/03require.t +++ b/cpan/version/t/03require.t @@ -19,7 +19,7 @@ BEGIN { # Don't want to use, because we need to make sure that the import doesn't # fire just yet (some code does this to avoid importing qv() and delare()). require_ok("version"); -is $version::VERSION, '0.9930', "Make sure we have the correct class"; +is $version::VERSION, '0.9932', "Make sure we have the correct class"; ok(!"main"->can("qv"), "We don't have the imported qv()"); ok(!"main"->can("declare"), "We don't have the imported declare()"); diff --git a/cpan/version/t/05sigdie.t b/cpan/version/t/05sigdie.t index 84a17a04b414..9ea225020068 100644 --- a/cpan/version/t/05sigdie.t +++ b/cpan/version/t/05sigdie.t @@ -14,7 +14,7 @@ BEGIN { } BEGIN { - use version 0.9930; + use version 0.9932; } pass "Didn't get caught by the wrong DIE handler, which is a good thing"; diff --git a/cpan/version/t/06noop.t b/cpan/version/t/06noop.t index b711da8bc5b3..8f60bbb61e9c 100644 --- a/cpan/version/t/06noop.t +++ b/cpan/version/t/06noop.t @@ -7,7 +7,7 @@ use Test::More qw/no_plan/; BEGIN { - use_ok('version', 0.9930); + use_ok('version', 0.9932); } my $v1 = 'version'->new('1.2'); diff --git a/cpan/version/t/07locale.t b/cpan/version/t/07locale.t index 69dafe61130f..12d2942d07cc 100644 --- a/cpan/version/t/07locale.t +++ b/cpan/version/t/07locale.t @@ -11,15 +11,29 @@ use Test::More tests => 8; use Config; BEGIN { - use_ok('version', 0.9930); + use_ok('version', 0.9932); +} + +sub radix { # Returns the radix character for the current locale. + + # Use localeconv() on earlier perls; if it is just a stub, assume a dot. + if (! $^V or $^V lt v5.37.4) { + return localeconv()->{decimal_point} || "."; + } + + # localeconv() may be a stub on some platforms. But on later perls, + # langinfo() will always exist and returns the best available value. + use if $^V && $^V ge v5.37.4, 'I18N::Langinfo' => qw(langinfo RADIXCHAR); + return langinfo(RADIXCHAR); } SKIP: { skip 'No locale testing for Perl < 5.6.0', 7 if $] < 5.006; skip 'No locale testing without d_setlocale', 7 if(!$Config{d_setlocale}); + eval "&POSIX::LC_NUMERIC"; skip 'No locale testing without LC_NUMERIC', 7 - if($Config{ccflags}) =~ /-DNO_LOCALE_NUMERIC\b/; + if $@ || $Config{ccflags} =~ /-DNO_LOCALE_NUMERIC\b/; # test locale handling my $warning = ''; @@ -37,11 +51,11 @@ SKIP: { while () { chomp; - $loc = setlocale( LC_ALL, $_); - last if $loc && localeconv()->{decimal_point} eq ','; + $loc = setlocale( LC_NUMERIC, $_); + last if $loc && radix() eq ','; } skip 'Cannot test locale handling without a comma locale', 6 - unless $loc and localeconv()->{decimal_point} eq ','; + unless $loc and radix() eq ','; setlocale(LC_NUMERIC, $loc); $ver = 1.23; # has to be floating point number @@ -57,7 +71,7 @@ SKIP: { $ver = 'version'->new($]); is "$ver", "$]", 'Use PV for dualvars'; } - setlocale( LC_ALL, $orig_loc); # reset this before possible skip + setlocale( LC_NUMERIC, $orig_loc); # reset this before possible skip skip 'Cannot test RT#46921 with Perl < 5.008', 1 if ($] < 5.008); my ($fh, $filename) = tempfile('tXXXXXXX', SUFFIX => '.pm', UNLINK => 1); @@ -68,10 +82,10 @@ use locale; use POSIX qw(locale_h); \$^W = 1; use version; -setlocale (LC_ALL, '$loc'); +setlocale (LC_NUMERIC, '$loc'); use version ; eval "use Socket 1.7"; -setlocale( LC_ALL, '$orig_loc'); +setlocale( LC_NUMERIC, '$orig_loc'); 1; EOF close $fh; @@ -324,3 +338,72 @@ wa_BE wa_BE@euro wa_BE.utf8 wa_BE.UTF-8 +Afrikaans +Albanian +Arabic +Basque +Breton +Brezhoneg +Bulgarian +Bulgarski +Chinese +Croatian +Cymraeg +Czech +Danish +Dansk +Deutsch +Dutch +Eesti +Ellada +Esperanto +Estonian +Euskaraz +Finnish +Flamish +Frysk +Gaeilge +Galego +Galician +German +Greek +Greenlandic +Hebrew +Hrvatski +Hungarian +Indonesian +Irish +Italian +Italiano +Japanese +Korean +Latin +Latine +Latvian +Lithuanian +Macedonian +Maltese +Moldovan +Nederlands +Nihongo +Norsk +Norwegian +Occitan +Polish +Polski +Rumanian +Russian +Russki +Serbian +Serbski +Slovak +Slovene +Slovenian +Sqhip +Suomi +Svenska +Swedish +Thai +Turkish +Welsh +Yiddish diff --git a/cpan/version/t/08_corelist.t b/cpan/version/t/08_corelist.t index 8ee803472588..b8e6cbb17a79 100644 --- a/cpan/version/t/08_corelist.t +++ b/cpan/version/t/08_corelist.t @@ -5,7 +5,7 @@ ######################### use Test::More tests => 3; -use_ok("version", 0.9930); +use_ok("version", 0.9932); # do strict lax tests in a sub to isolate a package to test importing SKIP: { diff --git a/cpan/version/t/09_list_util.t b/cpan/version/t/09_list_util.t index f7c33b9ac555..1ae6f78650d3 100644 --- a/cpan/version/t/09_list_util.t +++ b/cpan/version/t/09_list_util.t @@ -4,7 +4,7 @@ ######################### use strict; -use_ok("version", 0.9930); +use_ok("version", 0.9932); use Test::More; BEGIN { diff --git a/t/porting/customized.dat b/t/porting/customized.dat index 483f40ee0edb..4cd09b61efc0 100644 --- a/t/porting/customized.dat +++ b/t/porting/customized.dat @@ -21,4 +21,4 @@ podlators cpan/podlators/lib/Pod/Text.pm c454bab685ca35bccdcd8e87bc4a0922f6fc77f podlators cpan/podlators/lib/Pod/Text/Color.pm 318662cdfdd07a95be82c3080106ed1d410e18e0 podlators cpan/podlators/lib/Pod/Text/Overstrike.pm ac9e6c6483aa785a4cd9b0ded64130a52e5178c9 podlators cpan/podlators/lib/Pod/Text/Termcap.pm dc5c03b6310febae555202480bdcf8877c16efa8 -version cpan/version/lib/version.pm 8080cfe1fb21d5248c8ff5133b298d249d11e8e8 +version cpan/version/lib/version.pm 811b6efe5c5e02ad8dba4a6a8219811dc00f748e diff --git a/vutil.h b/vutil.h index 9484e2548389..0f3205362a41 100644 --- a/vutil.h +++ b/vutil.h @@ -47,6 +47,13 @@ static const char * Perl_prescan_version2(pTHX_ const char *s, bool strict, cons # define is_STRICT_VERSION(a,b) \ (a != Perl_prescan_version2(aTHX_ a, TRUE, b, NULL, NULL, NULL, NULL)) +#if PERL_VERSION_LT(5, 19, 1) +#undef LIKELY +#define LIKELY(cond) EXPECT(cBOOL(cond),TRUE) +#undef UNLIKELY +#define UNLIKELY(cond) EXPECT(cBOOL(cond),FALSE) +#endif + #else const char * Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv); diff --git a/vxs.inc b/vxs.inc index 80bb8ebad574..56ab03dd6b4e 100644 --- a/vxs.inc +++ b/vxs.inc @@ -46,6 +46,8 @@ {VXS_CLASS "::(0+", VXSp(version_numify), VXSXSDP(NULL)}, {VXS_CLASS "::numify", VXSp(version_numify), VXSXSDP(NULL)}, {VXS_CLASS "::normal", VXSp(version_normal), VXSXSDP(NULL)}, + {VXS_CLASS "::to_decimal", VXSp(version_to_decimal), VXSXSDP(NULL)}, + {VXS_CLASS "::to_dotted_decimal", VXSp(version_to_dotted_decimal), VXSXSDP(NULL)}, {VXS_CLASS "::(cmp", VXSp(version_vcmp), VXSXSDP(NULL)}, {VXS_CLASS "::(<=>", VXSp(version_vcmp), VXSXSDP(NULL)}, # ifdef PERL_CORE @@ -70,6 +72,8 @@ {VXS_CLASS "::qv", VXSp(version_qv), VXSXSDP(NULL)}, {VXS_CLASS "::declare", VXSp(version_qv), VXSXSDP(NULL)}, {VXS_CLASS "::is_qv", VXSp(version_is_qv), VXSXSDP(NULL)}, + {VXS_CLASS "::tuple", VXSp(version_tuple), VXSXSDP(NULL)}, + {VXS_CLASS "::from_tuple", VXSp(version_from_tuple), VXSXSDP(NULL)}, #else #ifndef dVAR @@ -296,6 +300,37 @@ VXS(version_normal) } } +VXS(version_to_decimal) +{ + dXSARGS; + SV* self = ST(0); + if (items < 1) + croak_xs_usage(cv, "lobj, ..."); + SP -= items; + { + SV *lobj, *rv; + VTYPECHECK(lobj, self, "lobj"); + rv = NEW_VERSION(VNUMIFY(lobj)); + VXS_RETURN_M_SV(sv_bless(rv, SvSTASH(SvRV(self)))); + } +} + +VXS(version_to_dotted_decimal) +{ + dXSARGS; + SV* self = ST(0); + if (items != 1) + croak_xs_usage(cv, "ver"); + SP -= items; + { + SV *lobj, *rv; + VTYPECHECK(lobj, self, "lobj"); + rv = NEW_VERSION(VNORMAL(lobj)); + sv_bless(rv, SvSTASH(SvRV(self))); + VXS_RETURN_M_SV(sv_bless(rv, SvSTASH(SvRV(self)))); + } +} + VXS(version_vcmp) { dXSARGS; @@ -446,4 +481,67 @@ VXS(version_is_qv) S_version_check_key(aTHX_ cv, "qv", 2); } +VXS(version_tuple) +{ + dXSARGS; + if (items != 1) + croak_xs_usage(cv, "lobj"); + SP -= items; + { + SV * lobj; + int i; + VTYPECHECK(lobj, ST(0), "lobj"); + + SV** avptr = hv_fetchs(MUTABLE_HV(lobj), "version", 0); + if (!avptr || !SvROK(*avptr) || SvTYPE(SvRV(*avptr)) != SVt_PVAV) { + PUTBACK; + return; + } + AV* version = MUTABLE_AV(SvRV(*avptr)); + for (i = 0; i < av_count(version); ++i) { + SV** svptr = av_fetch(version, i, 0); + if (!svptr || !*svptr) { + PUTBACK; + return; + } + XPUSHs(*svptr); + } + PUTBACK; + } +} + +VXS(version_from_tuple) +{ + dXSARGS; + SV *lobj; + int i; + if (items < 2) + croak_xs_usage(cv, "lobj, ..."); + lobj = ST(0); + SP -= items; + + AV* versions = newAV(); + SV* original = newSVpvs("v"); + + for (i = 1; i < items; ++i) { + if (SvIV(ST(i)) < 0) + Perl_croak(aTHX_ "Value %d in version is negative", SvIV(ST(i))); + UV value = SvUV(ST(i)); + av_push(versions, newSVuv(value)); + if (i != 1) + sv_catpvs(original, "."); + sv_catpvf(original, "%" UVuf, value); + } + + HV* hash = newHV(); + (void)hv_stores(hash, "version", newRV_noinc(MUTABLE_SV(versions))); + (void)hv_stores(hash, "original", original); + (void)hv_stores(hash, "qv", newSVsv(&PL_sv_yes)); + + HV* stash = SvROK(lobj) ? SvSTASH(lobj) : gv_stashsv(lobj, GV_ADD); + SV* result = sv_bless(newRV_noinc(MUTABLE_SV(hash)), stash); + XPUSHs(result); + PUTBACK; +} + #endif