class Gem::Version

Version 类将字符串版本处理为可比较的值。版本字符串通常应为一系列用句点分隔的数字。每个部分(用句点分隔的数字)都被视为其自身的数字,这些数字用于排序。例如,3.10 的排序高于 3.2,因为 10 大于 2。

如果任何部分包含字母(目前仅支持 a-z),则该版本被认为是预发布版本。在第 N 部分中具有预发布部分的版本排序低于具有 N-1 部分的版本。预发布部分使用普通的 Ruby 字符串排序规则按字母顺序排序。如果预发布部分同时包含字母和数字,它将被分成多个部分以提供预期的排序行为(1.0.a10 变为 1.0.a.10,并且大于 1.0.a9)。

预发布版本在实际发布版本之间排序(从最新到最旧)

  1. 1.0

  2. 1.0.b1

  3. 1.0.a.2

  4. 0.9

如果您想指定一个版本限制,该限制包括 1.x 系列的预发布版本和常规发布版本,这是最好的方法

s.add_dependency 'example', '>= 1.0.0.a', '< 2.0.0'

软件如何变更

用户希望能够指定一个版本约束,该约束使他们有合理的期望,即如果版本约束为真,则库的新版本将与他们的软件一起工作,如果版本约束为假,则不能与他们的软件一起工作。换句话说,完美的系统将接受库的所有兼容版本,并拒绝所有不兼容版本。

库以 3 种方式更改(好吧,不仅仅是 3 种,但请在此处保持专注!)。

  1. 更改可能只是实现细节,对客户端软件没有影响。

  2. 更改可能会添加新功能,但以与早期版本编写的客户端软件仍然兼容的方式进行。

  3. 更改可能会更改库的公共接口,从而使旧软件不再兼容。

此时一些示例是合适的。假设我有一个支持 pushpop 方法的 Stack 类。

第一类变更的示例:

第二类变更的示例可能包括:

第三类变更的示例可能包括:

RubyGems Rational 版本控制

示例

让我们使用上面的 Stack 示例来完成一个项目生命周期。

版本 0.0.1

初始 Stack 类已发布。

版本 0.0.2

切换到链表实现,因为它更酷。

版本 0.1.0

添加了一个 depth 方法。

版本 1.0.0

添加了 top 并使 pop 返回 nil(pop 过去返回旧的顶部项)。

版本 1.1.0

push 现在返回被推送的值(它过去返回 nil)。

版本 1.1.1

修复了链表实现中的一个错误。

版本 1.1.2

修复了上次修复中引入的错误。

客户端 A 需要具有基本 push/pop 功能的堆栈。他们编写原始接口(没有 top),因此他们的版本约束如下所示

gem 'stack', '>= 0.0'

本质上,任何版本对于客户端 A 来说都可以。对库的不兼容更改会导致他们感到痛苦,但他们愿意冒险(我们称客户端 A 为乐观)。

客户端 B 与客户端 A 类似,除了两件事:(1) 他们使用 depth 方法,并且 (2) 他们担心未来的不兼容性,因此他们编写的版本约束如下所示

gem 'stack', '~> 0.1'

depth 方法是在版本 0.1.0 中引入的,因此该版本或之后的任何版本都可以,只要版本保持在引入不兼容性的 1.0 版本以下即可。我们称客户端 B 为悲观,因为他们担心未来不兼容的更改(悲观是可以的!)。

防止 Version 灾难:

来自:www.zenspider.com/ruby/2008/10/rubygems-how-to-preventing-catastrophe.html

假设您依赖于 fnord gem 版本 2.y.z。如果您将依赖项指定为“>= 2.0.0”,那么您就没问题了,对吗?如果 fnord 3.0 发布并且它与 2.y.z 不向后兼容会发生什么?由于使用“>=”,您的东西会损坏。更好的方法是使用“approximate”版本说明符(“~>”)指定您的依赖项。它们有点令人困惑,因此这里介绍了依赖项说明符的工作方式

Specification From  ... To (exclusive)
">= 3.0"      3.0   ... &infin;
"~> 3.0"      3.0   ... 4.0
"~> 3.0.0"    3.0.0 ... 3.1
"~> 3.5"      3.5   ... 4.0
"~> 3.5.0"    3.5.0 ... 3.6
"~> 3"        3.0   ... 4.0

对于最后一个示例,单位数版本会自动用零扩展,以给出合理的结果。