@ -407,7 +407,18 @@ func VersionConstraintsString(spec VersionConstraints) string {
// and sort them into a consistent order.
sels := make ( map [ constraints . SelectionSpec ] struct { } )
for _ , sel := range spec {
sels [ sel ] = struct { } { }
// The parser allows writing abbreviated version (such as 2) which
// end up being represented in memory with trailing unconstrained parts
// (for example 2.*.*). For the purpose of serialization with Ruby
// style syntax, these unconstrained parts can all be represented as 0
// with no loss of meaning, so we make that conversion here. Doing so
// allows us to deduplicate equivalent constraints, such as >= 2.0 and
// >= 2.0.0.
normalizedSel := constraints . SelectionSpec {
Operator : sel . Operator ,
Boundary : sel . Boundary . ConstrainToZero ( ) ,
}
sels [ normalizedSel ] = struct { } { }
}
selsOrder := make ( [ ] constraints . SelectionSpec , 0 , len ( sels ) )
for sel := range sels {
@ -450,34 +461,26 @@ func VersionConstraintsString(spec VersionConstraints) string {
b . WriteString ( "??? " )
}
// The parser allows writing abbreviated version (such as 2) which
// end up being represented in memory with trailing unconstrained parts
// (for example 2.*.*). For the purpose of serialization with Ruby
// style syntax, these unconstrained parts can all be represented as 0
// with no loss of meaning, so we make that conversion here.
//
// This is possible because we use a different constraint operator to
// distinguish between the two types of pessimistic constraint:
// minor-only and patch-only. For minor-only constraints, we always
// want to display only the major and minor version components, so we
// special-case that operator below.
// We use a different constraint operator to distinguish between the
// two types of pessimistic constraint: minor-only and patch-only. For
// minor-only constraints, we always want to display only the major and
// minor version components, so we special-case that operator below.
//
// One final edge case is a minor-only constraint specified with only
// the major version, such as ~> 2. We treat this the same as ~> 2.0,
// because a major-only pessimistic constraint does not exist: it is
// logically identical to >= 2.0.0.
boundary := sel . Boundary . ConstrainToZero ( )
if sel . Operator == constraints . OpGreaterThanOrEqualMinorOnly {
// The minor-pessimistic syntax uses only two version components.
fmt . Fprintf ( & b , "%s.%s" , boundary. Major , b oundary. Minor )
fmt . Fprintf ( & b , "%s.%s" , sel. Boundary . Major , sel . B oundary. Minor )
} else {
fmt . Fprintf ( & b , "%s.%s.%s" , boundary. Major , boundary . Minor , b oundary. Patch )
fmt . Fprintf ( & b , "%s.%s.%s" , sel. Boundary . Major , sel . Boundary . Minor , sel . B oundary. Patch )
}
if sel . Boundary . Prerelease != "" {
b . WriteString ( "-" + b oundary. Prerelease )
b . WriteString ( "-" + sel. B oundary. Prerelease )
}
if sel . Boundary . Metadata != "" {
b . WriteString ( "+" + b oundary. Metadata )
b . WriteString ( "+" + sel. B oundary. Metadata )
}
}
return b . String ( )