Permalink
Browse files

Ignore underscores in `declare()`.

Seems like version.pm is a bit inconsistent when a version string is passed
that has underscores in it. So let it do its thing in `parse()`, but strip
them out in `declare()`. And even if it retains them in `parse()`, strip them
out and clean things up in `normal()`.
  • Loading branch information...
1 parent 9468f1b commit 2305ee77bccd3139d335c4d64cba9563122838fe @theory committed Sep 10, 2010
Showing with 54 additions and 26 deletions.
  1. +41 −18 lib/version/Semantic.pm
  2. +13 −8 t/base.t
View
@@ -49,6 +49,7 @@ sub declare {
(my $v = $ival) =~ s/($OPTIONAL_EXTRA_PART*)[[:space:]]*$//;
my $extra = $1;
+ $v =~ s/_//g; # ignore underscores.
my $self = $class->SUPER::declare($v);
$self->{extra} = $extra;
return $self;
@@ -72,14 +73,19 @@ sub stringify {
sub normal {
my $self = shift;
- (my $norm = $self->SUPER::normal . ($self->{extra} || ''));
- $norm =~ s/^v//;
- return $norm;
+ (my $norm = $self->SUPER::normal) =~ s/^v//;
+ if ($norm =~ s/_//g) {
+ # Seems messed up. Should have three parts and no leading 0s.
+ $norm = do {
+ no warnings;
+ join '.', map { int $_ } ( split /[.]/ => $norm )[0..2];
+ };
+ }
+ return $norm . ($self->{extra} || '');
}
sub numify { _die 'Semantic versions cannot be numified'; }
sub is_alpha { !!shift->{extra} }
-sub is_qv { 1 }
sub compare {
my ($left, $right, $rev) = @_;
@@ -206,31 +212,48 @@ more forgiving constructors.
my $semver = version::Semantic->declare('1.2'); # 1.2.0
-Similar to L<version>'s C<declare()> constructor, the parts of the version
-string parsed are always considered to be integers. This method will also fill
-in other missing parts.
-
-This constructor uses the most forgiving parser. Consider using it to
-normalize version strings.
+This parser strips out any underscores from the version string and passes it
+to to C<version>'s C<declare> 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<parse>
my $semver = version::Semantic->parse('1.2'); # 1.200.0
This parser dispatches to C<version>'s C<parse> constructor, which tries to be
-more flexible in how it converts simple decimal strings. Some examples: Not
-really recommended, but given the sorry history of version strings in Perl,
-it's gotta be there.
+more flexible in how it converts simple decimal strings and numbers. Not
+really recommended, since it's treatment of decimals is quit different from
+the dotted-integer format of semantic version strings, and thus can lead to
+inconsistencies. Included only for proper compatibility with L<version>.
=head2 Instance Methods
=head3 C<normal>
- my $str = $semver->normal;
-
-Returns a normalized representation of the version string. This string will
-always be a strictly-valid dotted-integer semantic version string suitable for
-passing to C<new()>.
+ version::Semantic->declare('v1.2')->normal; # 1.2.0
+ version::Semantic->parse('1.2')->normal; # 1.200.0
+ version::Semantic->declare('1.02.0b1')->normal; # 1.2.0b1
+ version::Semantic->parse('1.02_30')->normal # 1.230.0
+ version::Semantic->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<new()>. Unlike L<version>'s C<normal> method, there will be no leading
+"v".
+
+=head3 C<stringify>
+
+ version::Semantic->declare('v1.2')->stringify; # v1.2
+ version::Semantic->parse('1.200')->stringify; # v1.200
+ version::Semantic->declare('1.2b1')->stringify; # v1.2b1
+ version::Semantic->parse(1.02_30)->stringify; # v1.0230
+ version::Semantic->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<numify>
View
@@ -2,7 +2,7 @@
use strict;
use warnings;
-use Test::More tests => 388;
+use Test::More tests => 425;
#use Test::More 'no_plan';
my $CLASS;
@@ -198,27 +198,32 @@ for my $spec (
['1b', '1.0.0b'],
['9.0beta4', '9.0.0beta4'],
[' 012.2.2', '12.2.2'],
- ['99999998', '99999998.0.0'],
+ ['99999998', '99999998.0.0'],
+ ['1.02_30', '1.230.0'],
+ [1.02_30, '1.23.0'],
+ [3.4, '3.4.0', '3.400.0'],
) {
my $r = $CLASS->new($spec->[1]);
isa_ok my $l = version::Semantic->declare($spec->[0]), $CLASS, $spec->[0];
(my $string = $spec->[0]) =~ s/^\s+//;
$string =~ s/\s+$//;
- $string = "v$string" if $string =~ /^\d+[.][^.]+$/;
- is $l->stringify, $string, qq{... And it should stringify to "$string"};
- is $l->normal, $spec->[1], qq{... And it should normalize to "$spec->[1]"};
+ my $vstring = $string =~ /^\d+[.][^.]+$/ ? "v$string" : $string;
+ $vstring =~ s/_//g;
+ 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]"};
+ cmp_ok $spec->[0], '==', $r, qq{$r == "$spec->[0]"} unless $string =~ /_/;
if ($spec->[0] && $spec->[0] !~ /^[a-z]/ && $spec->[0] !~ /[.]{2}/) {
my $exp = $spec->[2] || $spec->[1];
isa_ok $l = version::Semantic->parse($spec->[0]), $CLASS,
"$spec->[0] should be parseable as a semver";
- is $l->normal, $exp, "... And it should be normalized to $exp";
+ 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};
+ cmp_ok $l, '==', $r, qq{$l == $r} unless $string =~ /_/;
}
}

0 comments on commit 2305ee7

Please sign in to comment.