SemVer-v0.7.0000755000000000000 013325567051 13443 5ustar00unknownunknown000000000000SemVer-v0.7.0/Build.PL000444000000000000 151713325566711 15102 0ustar00unknownunknown000000000000use strict; use warnings; use Module::Build; Module::Build->new( module_name => 'SemVer', license => 'perl', configure_requires => { 'Module::Build' => '0.30', }, build_requires => { 'Module::Build' => '0.30', 'Test::More' => '0.88', }, requires => { 'version' => 0.82, 'perl' => 5.008001, }, recommends => { 'Test::Pod' => '1.41', 'Test::Pod::Coverage' => '1.06', }, meta_merge => { resources => { homepage => 'http://search.cpan.org/dist/SemVer/', bugtracker => 'http://github.com/theory/semver/issues/', repository => 'http://github.com/theory/semver', } }, )->create_build_script; SemVer-v0.7.0/Build.bat000555000000000000 350513325567006 15335 0ustar00unknownunknown000000000000@rem = '--*-Perl-*-- @echo off if "%OS%" == "Windows_NT" goto WinNT perl -x -S "%0" --build_bat %1 %2 %3 %4 %5 %6 %7 %8 %9 goto endofperl :WinNT perl -x -S %0 --build_bat %* if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl if %errorlevel% == 9009 echo You do not have Perl in your PATH. if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul goto endofperl @rem '; #!perl #line 15 use strict; use Cwd; use File::Basename; use File::Spec; sub magic_number_matches { return 0 unless -e '_build\\magicnum'; my $FH; open $FH, '<','_build\\magicnum' or return 0; my $filenum = <$FH>; close $FH; return $filenum == 291315; } my $progname; my $orig_dir; BEGIN { $^W = 1; # Use warnings $progname = basename($0); $orig_dir = Cwd::cwd(); my $base_dir = 'D:\\Projects\\Perl\\JoK\\SemVer'; if (!magic_number_matches()) { unless (chdir($base_dir)) { die ("Couldn't chdir($base_dir), aborting\n"); } unless (magic_number_matches()) { die ("Configuration seems to be out of date, please re-run 'perl Build.PL' again.\n"); } } unshift @INC, ( ); } close(*DATA) unless eof(*DATA); # ensure no open handles to this script use Module::Build; Module::Build->VERSION(q{0}); # Some platforms have problems setting $^X in shebang contexts, fix it up here $^X = Module::Build->find_perl_interpreter; if (-e 'Build.PL' and not Module::Build->up_to_date('Build.PL', $progname)) { warn "Warning: Build.PL has been altered. You may need to run 'perl Build.PL' again.\n"; } # This should have just enough arguments to be able to bootstrap the rest. my $build = Module::Build->resume ( properties => { config_dir => '_build', orig_dir => $orig_dir, }, ); $build->dispatch; __END__ :endofperl SemVer-v0.7.0/Changes000444000000000000 351013325566711 15074 0ustar00unknownunknown000000000000Revision history for Perl extension SemVer. 0.7.0 2018-07-24T11:09:17Z - Implemented Semantic Versioning 2.0.0 specification - Updated tests for Semantic Versioning 2.0.0 - added testing for Perl 5.24, 5.26, 5.28 0.6.0 2015-01-23T05:07:58Z - Removed tests that fail on version.pm 0.9910 and higher due to trailing decimal sign. Thanks to Andreas Koenig for the report and diagnosis. - Fixed vstring warning on Perl 5.8. - Now skip tests that fail with version::vpp. - Now skip test on version.pm 0.9911 that fails with that version. - Now skip failing tests on Perl 5.8 and version.pm less than 0.9909. - Removed all Pod tests from the distribution. 0.5.0 2013-04-02T06:57:06Z - The `new()` now throws an exception when a version string has a prerelease version with no preceding dash. This is keep its requirement for strictness consistent. - Fixed a bug where a SemVer object passed to `new()` did not properly clone the dash preceding a prerelease version. 0.4.0 2012-11-20T18:59:33Z - Updated the parsers to support an optional dash before the prerelease version, and `normal()` to always emit a dash for the prerelease version. This brings it in line with the final semver 1.0.0 specification. 0.3.0 2011-05-26T04:54:50 - Made leading zeros, such as the "04" in "1.04.3" illegal when parsing via `new()`. - Eliminted "Use of qw(...) as parentheses is deprecated" in the tests when running on Perl 5.14. 0.2.0 2010-09-17T17:59:57 - Require Test::Pod 1.41 for testing POD because it supports `L`. 0.1.0 2010-09-16T19:07:04 - Initial version, created with lots of help and feedback from version.pm author John Peacock SemVer-v0.7.0/MANIFEST000444000000000000 15713325567051 14714 0ustar00unknownunknown000000000000Build.bat Build.PL Changes lib/SemVer.pm MANIFEST This list of files README.md t/base.t META.yml META.json SemVer-v0.7.0/META.json000444000000000000 265513325567051 15231 0ustar00unknownunknown000000000000{ "abstract" : "Use semantic version numbers", "author" : [ "unknown" ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4224", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "SemVer", "prereqs" : { "build" : { "requires" : { "Module::Build" : "0.30", "Test::More" : "0.88" } }, "configure" : { "requires" : { "Module::Build" : "0.30" } }, "runtime" : { "recommends" : { "Test::Pod" : "1.41", "Test::Pod::Coverage" : "1.06" }, "requires" : { "perl" : "5.008001", "version" : "0.82" } } }, "provides" : { "SemVer" : { "file" : "lib/SemVer.pm", "version" : "v0.7.0" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "http://github.com/theory/semver/issues/" }, "homepage" : "http://search.cpan.org/dist/SemVer/", "license" : [ "http://dev.perl.org/licenses/" ], "repository" : { "url" : "http://github.com/theory/semver" } }, "version" : "v0.7.0", "x_serialization_backend" : "JSON::PP version 2.94" } SemVer-v0.7.0/META.yml000444000000000000 154713325567051 15060 0ustar00unknownunknown000000000000--- abstract: 'Use semantic version numbers' author: - unknown build_requires: Module::Build: '0.30' Test::More: '0.88' configure_requires: Module::Build: '0.30' dynamic_config: 1 generated_by: 'Module::Build version 0.4224, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: SemVer provides: SemVer: file: lib/SemVer.pm version: v0.7.0 recommends: Test::Pod: '1.41' Test::Pod::Coverage: '1.06' requires: perl: '5.008001' version: '0.82' resources: bugtracker: http://github.com/theory/semver/issues/ homepage: http://search.cpan.org/dist/SemVer/ license: http://dev.perl.org/licenses/ repository: http://github.com/theory/semver version: v0.7.0 x_serialization_backend: 'CPAN::Meta::YAML version 0.018' SemVer-v0.7.0/README.md000444000000000000 722513325566711 15067 0ustar00unknownunknown000000000000SemVer version 0.7.0 ==================== This module subclasses [`version`] to create semantic versions, as defined by the [Semantic Versioning 2.0.0 Specification] The salient points of the specification, for the purposes of version formatting, are: 1. A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor version, and Z is the patch version. Each element MUST increase numerically. For instance: `1.9.0 < 1.10.0 < 1.11.0`. 2. A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers immediately following the patch version. Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes. Pre-release versions have a lower precedence than the associated normal version. A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version. Examples: `1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92`. 3. Build metadata MAY be denoted by appending a plus sign and a series of dot separated identifiers immediately following the patch or pre-release version. Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty. Build metadata SHOULD be ignored when determining version precedence. Thus two versions that differ only in the build metadata, have the same precedence. Examples: `1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85`. 4. Precedence refers to how versions are compared to each other when ordered. Precedence MUST be calculated by separating the version into major, minor, patch and pre-release identifiers in that order (Build metadata does not figure into precedence). Precedence is determined by the first difference when comparing each of these identifiers from left to right as follows: Major, minor, and patch versions are always compared numerically. Example: `1.0.0 < 2.0.0 < 2.1.0 < 2.1.1`. When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version. Example: `1.0.0-alpha < 1.0.0`. Precedence for two pre-release versions with the same major, minor, and patch version MUST be determined by comparing each dot separated identifier from left to right until a difference is found as follows: identifiers consisting of only digits are compared numerically and identifiers with letters or hyphens are compared lexically in ASCII sort order. Numeric identifiers always have lower precedence than non-numeric identifiers. A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal. Example: `1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0`. [`version`]: http://search.cpan.org/perldoc?version [Semantic Versioning 2.0.0 Specification]: http://semver.org/spec/v2.0.0.html Installation ============ To install this module, type the following: perl Build.PL ./Build ./Build test ./Build install Dependencies ------------ SemVer requires version. Copyright and License --------------------- Copyright (c) 2010-2018 David E. Wheeler. Some Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. SemVer-v0.7.0/lib000755000000000000 013325567051 14211 5ustar00unknownunknown000000000000SemVer-v0.7.0/lib/SemVer.pm000444000000000000 4350713325566711 16140 0ustar00unknownunknown000000000000package SemVer; use 5.008001; use strict; use version 0.82; use Scalar::Util (); use overload ( '""' => 'stringify', '<=>' => 'vcmp', 'cmp' => 'vcmp', ); our @ISA = qw(version); our $VERSION = '0.7.0'; # For Module::Build sub _die { require Carp; Carp::croak(@_) } # Prevent version.pm from mucking with our internals. sub import {} # Adapted from version.pm. my $STRICT_INTEGER_PART = qr/0|[1-9][0-9]*/; my $DOT_SEPARATOR = qr/\./; my $PLUS_SEPARATOR = qr/\+/; my $DASH_SEPARATOR = qr/-/; my $STRICT_DOTTED_INTEGER_PART = qr/$DOT_SEPARATOR$STRICT_INTEGER_PART/; my $STRICT_DOTTED_INTEGER_VERSION = qr/ $STRICT_INTEGER_PART $STRICT_DOTTED_INTEGER_PART{2,} /x; my $IDENTIFIER = qr/[-0-9A-Za-z]+/; my $DOTTED_IDENTIFIER = qr/(?:$DOT_SEPARATOR$IDENTIFIER)*/; my $PRERELEASE = qr/$IDENTIFIER$DOTTED_IDENTIFIER/; my $METADATA = qr/$IDENTIFIER$DOTTED_IDENTIFIER/; my $OPTIONAL_EXTRA_PART = qr/$PRERELEASE($PLUS_SEPARATOR$METADATA)?/; sub new { my ($class, $ival) = @_; # Handle vstring. return $class->SUPER::new($ival) if Scalar::Util::isvstring($ival); # Let version handle cloning. if (eval { $ival->isa('version') }) { my $self = $class->SUPER::new($ival); $self->{extra} = $ival->{extra}; $self->{dash} = $ival->{dash}; $self->_evalPreRelease($self->{extra}); return $self; } my ($val, $dash, $extra) = ( $ival =~ /^v?($STRICT_DOTTED_INTEGER_VERSION)(?:($DASH_SEPARATOR)($OPTIONAL_EXTRA_PART))?$/ ); _die qq{Invalid semantic version string format: "$ival"} unless defined $val; my $self = $class->SUPER::new($val); $self->{dash} = $dash; $self->{extra} = $extra; $self->_evalPreRelease($self->{extra}); return $self; } # Internal function to split up given string into prerelease- and patch-components sub _evalPreRelease { no warnings 'uninitialized'; my $self = shift; my $v = shift; my ($preRelease, $plus, $patch) = ( $v =~ /^($PRERELEASE)(?:($PLUS_SEPARATOR)($METADATA))?$/ ); @{$self->{prerelease}} = split $DOT_SEPARATOR,$preRelease; $self->{plus} = $plus; @{$self->{patch}} = (split $DOT_SEPARATOR, $patch || undef); return; } $VERSION = __PACKAGE__->new($VERSION); # For ourselves. sub declare { my ($class, $ival) = @_; return $class->new($ival) if Scalar::Util::isvstring($ival) or eval { $ival->isa('version') }; (my $v = $ival) =~ s/^v?$STRICT_DOTTED_INTEGER_VERSION(?:($DASH_SEPARATOR)($OPTIONAL_EXTRA_PART))[[:space:]]*$//; my $dash = $1; my $extra = $2; $v += 0 if $v =~ s/_//g; # ignore underscores. my $self = $class->SUPER::declare($v); $self->{dash} = $dash; $self->{extra} = $extra; $self->_evalPreRelease($self->{extra}); return $self; } sub parse { my ($class, $ival) = @_; return $class->new($ival) if Scalar::Util::isvstring($ival) or eval { $ival->isa('version') }; (my $v = $ival) =~ s/^v?$STRICT_DOTTED_INTEGER_VERSION(?:($DASH_SEPARATOR)($OPTIONAL_EXTRA_PART))[[:space:]]*$//; my $dash = $1; my $extra = $2; $v += 0 if $v =~ s/_//g; # ignore underscores. my $self = $class->SUPER::parse($v); $self->{dash} = $dash; $self->{extra} = $extra; $self->_evalPreRelease($self->{extra}); return $self; } sub stringify { my $self = shift; my $str = $self->SUPER::stringify; # This is purely for SemVers constructed from version objects. $str += 0 if $str =~ s/_//g; # ignore underscores. return $str . ($self->{dash} || '') . ($self->{extra} || ''); } sub normal { my $self = shift; (my $norm = $self->SUPER::normal) =~ s/^v//; $norm =~ s/_/./g; return $norm . ($self->{extra} ? "-$self->{extra}" : ''); } sub numify { _die 'Semantic versions cannot be numified'; } sub is_alpha { !!shift->{extra} } # Sort Ordering: # Precedence refers to how versions are compared to each other when ordered. Precedence MUST be calculated by # separating the version into major, minor, patch and pre-release identifiers in that order (Build metadata does not figure into precedence). # Precedence is determined by the first difference when comparing each of these identifiers from left to right as follows: # 1. Major, minor, and patch versions are always compared numerically. Example: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1. # 2. When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version. # Example: 1.0.0-alpha < 1.0.0. # 3. Precedence for two pre-release versions with the same major, minor, and patch version MUST be determined by # comparing each dot separated identifier from left to right until a difference is found as follows: # 3.a. identifiers consisting of only digits are compared numerically and identifiers with letters or hyphens are # compared lexically in ASCII sort order. # 3.b. Numeric identifiers always have lower precedence than non-numeric identifiers. # 3.c. A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal. # Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0. sub vcmp { my $left = shift; my $right = ref($left)->declare(shift); # Reverse? ($left, $right) = shift() ? ($right, $left): ($left, $right); # Major and minor win. - case 1. if (my $ret = $left->SUPER::vcmp($right, 0)) { return $ret; } else { #cases 2, 3 my $lenLeft = 0; my $lenRight = 0; if (defined $left->{prerelease}) { $lenLeft = scalar(@{$left->{prerelease}}); } if (defined $right->{prerelease}) { $lenRight = scalar(@{$right->{prerelease}}); } my $lenMin = ($lenLeft, $lenRight)[$lenLeft > $lenRight]; if ( $lenLeft == 0) { if ($lenRight == 0) { return 0; # Neither LEFT nor RIGHT have prerelease identifiers - versions are equal } else { # Case 2: When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version. return 1; # Only RIGHT has prelease - not LEFT -> LEFT wins } } else { if ($lenRight == 0) { # Case 2: When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version. return -1; # Only LEFT has prelease identifiers - not RIGHT -> RIGHT wins } else { # LEFT and RIGHT have prelease identifiers - compare each part separately for (my $i = 0; $i < $lenMin; $i++) { my $isNumLeft = Scalar::Util::looks_like_number($left->{prerelease}->[$i]); my $isNumRight = Scalar::Util::looks_like_number($right->{prerelease}->[$i]); # Case 3.b: Numeric identifiers always have lower precedence than non-numeric identifiers if (!$isNumLeft && $isNumRight) { return 1; # LEFT identifier is Non-numeric - RIGHT identifier is numeric -> LEFT wins } elsif ($isNumLeft && !$isNumRight) { return -1; # LEFT identifier is numeric - RIGHT identifier is non-numeric -> RIGHT wins } elsif ($isNumLeft && $isNumRight) { # Case 3.a.1: identifiers consisting of only digits are compared numerically if ($left->{prerelease}->[$i] == $right->{prerelease}->[$i] ) { next; # LEFT identifier and RIGHT identifier are equal - step to next part } elsif ($left->{prerelease}->[$i] > $right->{prerelease}->[$i] ) { return 1; # LEFT identifier is bigger than RIGHT identifier -> LEFT wins } else { return -1; return 1; # LEFT identifier is smaller than RIGHT identifier -> RIGHT wins } } else { # Case 3.a.2: identifiers with letters or hyphens are compared lexically in ASCII sort order. if (lc $left->{prerelease}->[$i] eq lc $right->{prerelease}->[$i] ) { next; # LEFT identifier and RIGHT identifier are equal - step to next part } elsif (lc $left->{prerelease}->[$i] gt lc $right->{prerelease}->[$i] ) { return 1; # LEFT identifier is bigger than RIGHT identifier -> LEFT wins } else { return -1; return 1; # LEFT identifier is smaller than RIGHT identifier -> RIGHT wins } } } # Case 3.c: A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal if ($lenLeft > $lenRight) { return 1; # All existing identifiers are equal, but LEFT has more identifiers -> LEFT wins } elsif ($lenLeft < $lenRight) { return -1; # All existing identifiers are equal, but RIGHT has more identifiers -> RIGHT wins } # All identifiers are equal return 0; } } } } 1; __END__ =head1 Name SemVer - Use semantic version numbers =head1 Synopsis use SemVer; our $VERSION = SemVer->new('1.2.0-b1'); =head1 Description This module subclasses L to create semantic versions, as defined by the L. The three salient points of the specification, for the purposes of version formatting, are: =over =item 1. A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor version, and Z is the patch version. Each element MUST increase numerically. For instance: C<< 1.9.0 -> 1.10.0 -> 1.11.0 >>. =item 2. A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers immediately following the patch version. Identifiers MUST comprise only ASCII alphanumerics and hyphen C<[0-9A-Za-z-]>. Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes. Pre-release versions have a lower precedence than the associated normal version. A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version: C<< 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92 >> =item 3. Build metadata MAY be denoted by appending a plus sign and a series of dot separated identifiers immediately following the patch or pre-release version. Identifiers MUST comprise only ASCII alphanumerics and hyphen C<[0-9A-Za-z-]>. Identifiers MUST NOT be empty. Build metadata SHOULD be ignored when determining version precedence. Thus two versions that differ only in the build metadata, have the same precedence. Examples: C<< 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85 >>. =back =head2 Usage For strict parsing of semantic version numbers, use the C constructor. If you need something more flexible, use C. And if you need something more comparable with what L expects, try C. Compare how these constructors deal with various version strings (with values shown as returned by C: Argument | new | declare | parse -------------+----------+--------------------------- '1.0.0' | 1.0.0 | 1.0.0 | 1.0.0 '5.5.2-b1' | 5.5.2-b1 | 5.5.2-b1 | 5.5.2-b1 '1.05.0' | | 1.5.0 | 1.5.0 '1.0' | | 1.0.0 | 1.0.0 ' 012.2.2' | | 12.2.2 | 12.2.2 '1.1' | | 1.1.0 | 1.100.0 1.1 | | 1.1.0 | 1.100.0 '1.1.0b1' | | 1.1.0-b1 | 1.1.0-b1 '1.1-b1' | | 1.1.0-b1 | 1.100.0-b1 '1.2.b1' | | 1.2.0-b1 | 1.2.0-b1 '9.0-beta4' | | 9.0.0-beta4 | 9.0.0-beta4 '9' | | 9.0.0 | 9.0.0 '1-b' | | 1.0.0-b | 1.0.0-b 0 | | 0.0.0 | 0.0.0 '0-rc1' | | 0.0.0-rc1 | 0.0.0-rc1 '1.02_30' | | 1.23.0 | 1.23.0 1.02_30 | | 1.23.0 | 1.23.0 Note that, unlike in L, the C and C methods ignore underscores. That is, version strings with underscores are treated as decimal numbers. Hence, the last two examples yield exactly the same semantic versions. As with L objects, the comparison and stringification operators are all overloaded, so that you can compare semantic versions. You can also compare semantic versions with version objects (but not the other way around, alas). Boolean operators are also overloaded, such that all semantic version objects except for those consisting only of zeros are considered true. =head1 Interface =head2 Constructors =head3 C my $semver = SemVer->new('1.2.2'); Performs a validating parse of the version string and returns a new semantic version object. If the version string does not adhere to the semantic version specification an exception will be thrown. See C and C for more forgiving constructors. =head3 C my $semver = SemVer->declare('1.2'); # 1.2.0 This parser strips out any underscores from the version string and passes it to to C's C constructor, which always creates dotted-integer version objects. This is the most flexible way to declare versions. Consider using it to normalize version strings. =head3 C my $semver = SemVer->parse('1.2'); # 1.200.0 This parser dispatches to C's C constructor, which tries to be more flexible in how it converts simple decimal strings and numbers. Not really recommended, since it's treatment of decimals is quite different from the dotted-integer format of semantic version strings, and thus can lead to inconsistencies. Included only for proper compatibility with L. =head2 Instance Methods =head3 C SemVer->declare('v1.2')->normal; # 1.2.0 SemVer->parse('1.2')->normal; # 1.200.0 SemVer->declare('1.02.0-b1')->normal; # 1.2.0-b1 SemVer->parse('1.02_30')->normal # 1.230.0 SemVer->parse(1.02_30)->normal # 1.23.0 Returns a normalized representation of the version. This string will always be a strictly-valid dotted-integer semantic version string suitable for passing to C. Unlike L's C method, there will be no leading "v". =head3 C SemVer->declare('v1.2')->stringify; # v1.2 SemVer->parse('1.200')->stringify; # v1.200 SemVer->declare('1.2-r1')->stringify; # v1.2-r1 SemVer->parse(1.02_30)->stringify; # v1.0230 SemVer->parse(1.02_30)->stringify; # v1.023 Returns a string that is as close to the original representation as possible. If the original representation was a numeric literal, it will be returned the way perl would normally represent it in a string. This method is used whenever a version object is interpolated into a string. =head3 C Throws an exception. Semantic versions cannot be numified. Just don't go there. =head3 C my $is_alpha = $semver->is_alpha; Returns true if an ASCII string is appended to the end of the version string. This also means that the version number is a "special version", in the semantic versioning specification meaning of the phrase. =head3 C Compares the semantic version object to another version object or string and returns 0 if they're the same, -1 if the invocant is smaller than the argument, and 1 if the invocant is greater than the argument. Mostly you don't need to worry about this: Just use the comparison operators instead. They will use this method: if ($semver < $another_semver) { die "Need $another_semver or higher"; } Note that in addition to comparing other semantic version objects, you can also compare regular L objects: if ($semver < $version) { die "Need $version or higher"; } You can also pass in a version string. It will be turned into a semantic version object using C. So if you're using integer versions, you may or may not get what you want: my $semver = version::Semver->new('1.2.0'); my $version = '1.2'; my $bool = $semver == $version; # true If that's not what you want, pass the string to C first: my $semver = version::Semver->new('1.2.0'); my $version = version::Semver->parse('1.2'); # 1.200.0 my $bool = $semver == $version; # false =head1 See Also =over =item * L. =item * L =item * L =back =head1 Support This module is managed in an open L. Feel free to fork and contribute, or to clone L and send patches! Found a bug? Please L or L a report! =head1 Acknowledgements Many thanks to L author John Peacock for his suggestions and debugging help. =head1 Authors =over =item * David E. Wheeler =item * Johannes Kilian =back =head1 Copyright and License Copyright (c) 2010-2018 David E. Wheeler. Some Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut SemVer-v0.7.0/t000755000000000000 013325567051 13706 5ustar00unknownunknown000000000000SemVer-v0.7.0/t/base.t000444000000000000 2340213325566711 15165 0ustar00unknownunknown000000000000#!/usr/bin/perl -w use strict; use warnings; use Test::More tests => 610; #use Test::More 'no_plan'; use FindBin qw($Bin); use lib "$Bin/../lib"; my $CLASS; BEGIN { $CLASS = 'SemVer'; use_ok $CLASS or die; } diag 'Testing with version v', version->VERSION; can_ok $CLASS, qw( new declare parse normal numify is_alpha is_qv vcmp ); # Try the basics. isa_ok my $version = $CLASS->new('0.1.0'), $CLASS, 'An instance'; isa_ok $SemVer::VERSION, $CLASS, q{SemVer's own $VERSION}; my $is_vpp = !!grep { $_ eq 'version::vpp' } @version::ISA; for my $v (qw( 1.2.2 0.2.2 1.2.2 0.0.0 0.1.999 9999.9999999.823823 1.0.0-beta1 1.0.0-beta2 1.0.0 0.0.0-rc1 v1.2.2 999993333.0.0 )) { isa_ok my $semver =$CLASS->new($v), $CLASS, "new($v)"; my $str = $v =~ /^v/ ? substr $v, 1 : $v; is "$semver", $str, qq{$v should stringify to "$str"}; $str =~ s/(\d)([a-z].+)$/$1-$2/; is $semver->normal, $str, qq{$v should normalize to "$str"}; SKIP: { skip 'Boolean comparison broken with version::vpp', 1, $is_vpp; if ($v =~ /0\.0\.0/) { ok !$semver, "$v should be false"; } else { ok !!$semver, "$v should be true"; } } ok $semver->is_qv, "$v should be dotted-decimal"; my $is_alpha = $semver->is_alpha; if ($v =~ /[.]\d+-?[a-z]/) { ok $is_alpha, "$v should be alpha"; } else { ok !$is_alpha, "$v should not be alpha"; } } local $@; eval { $CLASS->new('') }; ok $@, 'Empty string should be an invalid version'; for my $bv (qw( 1.2 0 0.0 1.2b 1.b 1.04.0 1.65.r2 )) { local $@; eval { $CLASS->new($bv) }; like $@, qr{Invalid semantic version string format: "$bv"}, qq{"$bv" should be an invalid semver}; } # Try a vstring. isa_ok $version = $CLASS->new(v2.3.2), $CLASS, 'vstring version'; is $version->stringify, 'v2.3.2', 'vestring should stringify with "v"'; is $version->normal, '2.3.2', 'vstring should normalize without "v"'; # Try a shorter vstring. my $no_2digitvst = $] < 5.10 && version->VERSION < 0.9910; SKIP: { skip 'Two-integer vstrings weak on Perl 5.8', 3 if $no_2digitvst; isa_ok $version = $CLASS->new(v2.3), $CLASS, 'vstring version'; is $version->stringify, 'v2.3', 'short vestring should stringify with "v"'; is $version->normal, '2.3.0', 'short vstring should normalize without required 0'; } # Try another SemVer. isa_ok my $cloned = $CLASS->new($version), $CLASS, 'Cloned SemVer'; is $cloned->stringify, $version->stringify, 'Cloned stringify like original'; is $cloned->normal, $version->normal, 'Cloned should normalize like original'; # Try a SemVer with alpha. isa_ok $version = $CLASS->new('2.3.2-b1'), $CLASS, 'new version'; isa_ok $cloned = $CLASS->new($version), $CLASS, 'Second cloned SemVer'; is $cloned->stringify, $version->stringify, 'Second cloned stringify like original'; is $cloned->normal, $version->normal, 'Second cloned should normalize like original'; # Numify should die local $@; eval { $version->numify }; like $@, qr{Semantic versions cannot be numified}, 'Should get error from numify()'; # Now do some comparisons. Start with equivalents. for my $spec ( [ '1.2.2', '1.2.2' ], [ '1.2.23', '1.2.23' ], [ '0.0.0', '0.0.0' ], [ '999.888.7777', '999.888.7777' ], [ '0.1.2-beta3', '0.1.2-beta3' ], [ '1.0.0-rc-1', '1.0.0-RC-1' ], ) { my $l = $CLASS->new($spec->[0]); my $r = $CLASS->new($spec->[1]); is $l->vcmp($r), 0, "$l->vcmp($r) == 0"; is $l <=> $r, 0, "$l <=> $r == 0"; is $r <=> $l, 0, "$r <=> $l == 0"; cmp_ok $l, '==', $r, "$l == $r"; cmp_ok $l, '==', $r, "$l == $r"; cmp_ok $l, '<=', $r, "$l <= $r"; cmp_ok $l, '>=', $r, "$l >= $r"; is $l cmp $r, 0, "$l cmp $r == 0"; is $r cmp $l, 0, "$r cmp $l == 0"; cmp_ok $l, 'eq', $r, "$l eq $r"; cmp_ok $l, 'eq', $r, "$l eq $r"; cmp_ok $l, 'le', $r, "$l le $r"; cmp_ok $l, 'ge', $r, "$l ge $r"; } # Test not equal. for my $spec ( ['1.2.2', '1.2.3'], ['0.0.1', '1.0.0'], ['1.0.1', '1.1.0'], ['1.1.1', '1.1.0'], ['1.2.3-b', '1.2.3'], ['1.2.3', '1.2.3-b'], ['1.2.3-a', '1.2.3-b'], ['1.2.3-aaaaaaa1', '1.2.3-aaaaaaa2'], ) { my $l = $CLASS->new($spec->[0]); my $r = $CLASS->new($spec->[1]); cmp_ok $l->vcmp($r), '!=', 0, "$l->vcmp($r) != 0"; cmp_ok $l, '!=', $r, "$l != $r"; cmp_ok $l, 'ne', $r, "$l ne $r"; } # Test >, >=, <, and <=. for my $spec ( ['2.2.2', '1.1.1'], ['2.2.2', '2.1.1'], ['2.2.2', '2.2.1'], ['2.2.2-b', '2.2.1'], ['2.2.2', '2.2.2-b'], ['2.2.2-c', '2.2.2-b'], ['2.2.2-rc-2', '2.2.2-RC-1'], ['0.9.10', '0.9.9'], ) { my $l = $CLASS->new($spec->[0]); my $r = $CLASS->new($spec->[1]); cmp_ok $l->vcmp($r), '>', 0, "$l->vcmp($r) > 0"; cmp_ok $r->vcmp($l), '<', 0, "$r->vcmp($l) < 0"; cmp_ok $l, '>', $r, "$l > $r"; cmp_ok $l, '>=', $r, "$l >= $r"; cmp_ok $r, '<', $l, "$r < $l"; cmp_ok $r, '<=', $l, "$r <= $l"; cmp_ok $l, 'gt', $r, "$l gt $r"; cmp_ok $l, 'ge', $r, "$l ge $r"; cmp_ok $r, 'lt', $l, "$r lt $l"; cmp_ok $r, 'le', $l, "$r le $l"; } # Compare Versions from SemVer 2.0 my @ver = ("0.9.0","1.0.0-alpha","1.0.0-alpha.1","1.0.0-alpha.beta","1.0.0-beta","1.0.0-beta.2","1.0.0-beta.11","1.0.0-beta.31","1.0.0-beta.200","1.0.0-rc.1","1.0.0","2.0.0","2.1.0","2.1.1"); for (my $i = 0; $i < (scalar(@ver)-1); $i++) { for (my $j = $i+1; $j < scalar(@ver); $j++) { my $l = SemVer->new($ver[$i]); my $r = SemVer->new($ver[$j]); cmp_ok $l, '<', $r, "$l < $r"; } } # Compare to version objects. my $semver = $CLASS->new('1.2.0'); for my $v (qw( 1.002 1.2.0 v1.002 v1.2.0 )) { my $version = version->new($v); ok $semver == $version, "$semver == $version"; } # Compare to strings. for my $v (qw( 1.2.0 v1.2.0 )) { my $semver = $CLASS->new($v); cmp_ok $semver, '==', $v, qq{$semver == "$v"}; cmp_ok $v, '==', $semver, qq{"$v" == $semver}; cmp_ok $semver, 'eq', $v, qq{$semver eq "$v"}; cmp_ok $v, 'eq', $semver, qq{"$v" eq $semver}; } # Test declare() and parse. for my $spec ( ['1.2.2', '1.2.2'], ['01.2.2', '1.2.2'], ['1.02.2', '1.2.2'], ['1.2.02', '1.2.2'], # ['1.2.02b', '1.2.2-b'], # ['1.2.02beta-3 ', '1.2.2-beta-3'], # ['1.02.02rc1', '1.2.2-rc1'], ['1.0', '1.0.0'], ['1.1', '1.1.0', '1.100.0'], [ 1.1, '1.1.0', '1.100.0'], # ['1.1b1', '1.1.0-b1', '1.100.0-b1'], # ['1b', '1.0.0-b'], # ['9.0beta4', '9.0.0-beta4'], [' 012.2.2', '12.2.2'], ['99999998', '99999998.0.0'], ['1.02_30', '1.23.0'], [1.02_30, '1.23.0'], [3.4, '3.4.0', '3.400.0'], [3.04, '3.4.0', '3.40.0' ], ['3.04', '3.4.0', '3.40.0' ], [v3.4, '3.4.0' ], [9, '9.0.0' ], ['9', '9.0.0' ], ['0', '0.0.0' ], [0, '0.0.0' ], # ['0rc1', '0.0.0-rc1' ], ) { SKIP: { skip 'Two-integer vstrings weak on Perl 5.8', 12 if $no_2digitvst && Scalar::Util::isvstring($spec->[0]); my $r = $CLASS->new($spec->[1]); isa_ok my $l = SemVer->declare($spec->[0]), $CLASS, "Declared $spec->[0]"; my $string = Scalar::Util::isvstring($spec->[0]) ? join '.', map { ord } split // => $spec->[0] : $spec->[0]; $string =~ s/^\s+//; $string =~ s/\s+$//; $string += 0 if $string =~ s/_//g; my $vstring = $string =~ /^\d+[.][^.]+$/ ? "v$string" : $string; SKIP: { skip 'Stringification broken with version::vpp', 1, $is_vpp; is $l->stringify, $vstring, qq{... And it should stringify to "$vstring"}; } is $l->normal, $spec->[1], qq{... And it should normalize to "$spec->[1]"}; # Compare the non-semantic version string to the semantic one. cmp_ok $spec->[0], '==', $r, qq{$r == "$spec->[0]"}; if ($spec->[0] && $spec->[0] !~ /^[a-z]/ && $spec->[0] !~ /[.]{2}/) { my $exp = $spec->[2] || $spec->[1]; isa_ok $l = SemVer->parse($spec->[0]), $CLASS, "Parsed $spec->[0]"; $string = "v$string" if Scalar::Util::isvstring($spec->[0]); $string =~ s/_//; is $l->stringify, $string, "... And it should stringify to $string"; is $l->normal, $exp, "... And it should normalize to $exp"; # Try with the parsed version. $r = $CLASS->new($spec->[2]) if $spec->[2]; cmp_ok $l, '==', $r, qq{$l == $r} unless $string =~ /_/; } # Try creating as a version object and cloning. if ($spec->[0] !~ /[a-z]/i) { isa_ok my $v = version->parse($spec->[0]), 'version', "base version $spec->[0]"; isa_ok my $sv = SemVer->new($v), 'SemVer', "SemVer from base version $spec->[0]"; is $sv->stringify, $string, qq{... And it should stringify to "$vstring"}; SKIP: { skip 'version 0.9911 broke alpha->normal()', 1, if $spec->[0] =~ /_/ && version->VERSION == 0.9911; is $sv->normal, $l->normal, '... And it should normalize to "' . $l->normal . '"'; } } }} for my $v (qw( 1.2.02b 1.2.02beta-3 1.02.02rc1 1.1b1 1b 9.0beta4 0rc1 )) { eval { my $l = SemVer->declare($v); }; if ($@) { is 1, 1, $v.' is not a SemVer'; } else { is 1, 0, $v.' should not be not a SemVer'; } }