构建一个 Ruby Gem 第六章 版本

版本

bunder 这个 gem 使得 ruby 的依赖管理比起几年前要容易多了。Bunder 强势集成进了 Rails,但是也可以在任何 Ruby 程序中使用。对于我写的几个 Sinatra 程序,我通常写一个已经集成了 bundler 的自定义模板

如果你熟悉 Rails,你大概能认出下面的 Gemfile

source 'https://rubygems.org'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.0.2'

# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0'

# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'

# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'

有一件事需要注意那就是每一个 gem 都限制了一个特别的版本。如果这个版本没有被限制,程序有可能不能正常工作。

大概你已经知道了,一旦一个 gem 被加到 Gemfile 中,它可以被通过在程序的根目录运行 bundle install 来安装,或者仅仅运行 bundle (install 是默认命令)

语义化版本

总体来说,Ruby 社区遵从 语义化版本 (后面再细说)。语义化版本给我们指导当我们打破了我们的代码的接口时。Ruby 核心团队最近宣布了 Ruby 将会在 2.1.0 之后遵从语义化版本

Rails 官方没有遵从语义化版本,但是它倾向与把大型的特性改变归并在某个版本。

所以什么是语义化版本呢?

有整部的书关于版本实践,所以我不想对你啰嗦了。语义化版本的网站 是至今最好的学习资源。然而, 宏观上看,破坏性的常见应该被限制在特定的发布版本中。

比如, 假设我们维护一个当前版本是 1.5 的 gem. 如果我们打算加入一个功能而不影响(这点很重要)gem的其他部分的工作方式, 我们应该发布一个次要的版本(在原来的基础上递增), 版本 1.6 .

假设我们在1.6版本增加了新的功能, 我们之后意识到新的代码有一个bug. 我们修复了这个bug并且随后发布了一个补丁版本, 应该是 1.6.1 .

在一年的开发后, 我们认识到gem的某个部分非常糟糕并且我们想要重构. 在重构的过程中, 我们已经决定永久的改变公共接口. 因为这些改变不会向后兼容, 我们将会发布一个新的主版本 2.0.0.

让我们看看我们如何在我们的 gem 中运用这些.

没有版本

在 Gemfile 中加入一个没有指定版本的 gem 是符合语法的:

source 'https://rubygems.org'
gem 'rails'

运行 bundle install 的结果将会根据是否特定版本已经被安装了而不同。规则就像这样:

  • 如果 gem 已经在系统中存在了, 最新的被安装版本会被使用。

  • 如果 gem 没有被安装到系统中, 最新的稳定版会被安装并使用。

可以很容易地看到,取决于系统可能会产生不同的结果。编写应用程序已经很难了,就不要因为指定没有版本限制的依赖性而引进更多的挑战了。

准确的版本

这个 gemfile 是一个新的 Rails 4.0.2 程序生成的。因此Gemfile的第一行是这样的。

gem 'rails', '4.0.2'

指定版本作为一个额外的参数将会使用并且只使用那个版本。这种方式的问题就是经常会出现依赖同一个 gem 的不同版本。如果由于某些原因我们安装了两个 gem 依赖于 multi_json 这个 gem,但是每一个都指定了不同的版本,我们就有可能碰到问题并且得到意外的结果。

由于很多程序都依赖于一些 gems,依赖树就会变得复杂并且难以管理,我并不是说指定一个特定的 gem 版本是不好的,因为它不是。任何事物都有它适用的情况。但是如果你觉的要这样做,确保你有一个好的理由。否则,我建议使用下面的方法之一。

乐观版本约束

进一步来说,我们可以使用下面的语法来指定一个某个版本的 gem 是被允许使用:

gem 'sucker_punch', '>= 1.0'

如果你知道一个 gem 的某些特性或者改变,并且你想要确保用户不使用之前的版本,使用上面的语法是有效的。

我还没见过一个 Rubyist 有时间和精力来跟踪他们使用的 gem 的变化。我们作为开发者的责任是确保我们的程序可以像预期的那样工作。当我们依赖第三方的代码时,一切都变了。人们决定停止不停的工作。他们也通常会低调的发布新的版本。

这意味着如果我们使用上面的语法在 Gemfile 中并且接着打算发布 sucker_punch 2.0 而不向后兼容,那就糟糕了。 虽然这比不指定版本要好点,但是我们能做的更好。

悲观版本约束

正如我们在语义化版本中所看到的,在版本之间有一个安全地带。我们可以假设在下一个主版本之前没有不向后兼容的问题。 然而,如果我们依赖版本 1.2 或更高,版本 2.0 会弄坏我们的程序。

使用 『悲观』版本约束:

gem 'sass-rails', '~> 4.0.0'

这约束了 sass-rails 的版本在 4.0.04.1.0 之间。正如我们在语义化版本中看到的,一个补丁的发布是用来修复 bug 的。
如果某一个bug在 4.0.0 并且我们没有看到他们的发布通告,我们可能会受到影响。上面的语法允许 sass-rails gem 被更新当版本 4.0 的补丁被发布时。

在使用这个语法时版本的小数是很重要的。比如,假设上面的写法变成:

gem 'sass-rails', '~> 4.0'

这样的写法表示我愿意接受 sass-rails 这个 gem 的任何补丁(比如 4.0.1) 或者次要版本的发布 (比如 4.1, 4.2)。

虽然语法的改变很小,但是它对在依赖时的行为造成了巨大的变化。
有了这样的方式,让我们来看看它是如何影响我们的(作为 gem 的作者)。

Gemspec 依赖

在第二章中,我们加入了一些开发时的依赖到我们的 gem spec:

spec.add_development_dependency "bundler", "~> 1.3" 
spec.add_development_dependency "rake" 
spec.add_development_dependency "rspec" 
spec.add_development_dependency "pr

注意默认的 gemspec 建议 bundler 允许 bunlder 被更新到 1.4 或者 1.5,但不是主版本 (2.0)。我们可以照着处理我们的 gem 的生产环境和开发环境的依赖。

因为开发时依赖是关于本地开发的体验,所以宽松的处理是没什么问题的。最糟糕的情况就是一个贡献者会在开发时碰到一些问题。如果这是个问题的话,希望他们会提一个 issus 或者最好提一个 pull request!

注意:当我们加入依赖时,花点时间去看看这个依赖和作者是否遵循了语义化版本。但愿他们在他们的 gem 的 README 中说明了这一点( jquery.turbolinks 是一个很好的例子),否则就问问他们。这样,你就能搞清楚可能会打破变化的版本是如何被发布的并且可以更好的加入依赖到你的系统中。如果你不满足于你找到的信息,也许硬编码一个指定的版本或者找到一个替代的 gem 是更好的做法。

总结

当开始一个新的 gem 时,我推荐使用语义化版本。如果你没这样做,你要在 REAMDE 中说明这一点这样用户可以明确的知道。社区越是接受语义化版本,我们的版本标准就越可靠。很多人都不会在版本号上想太多,仅仅修复一个 bug 就发布一个新版本。

语义化版本的好处不仅仅在于小的 bug 修复,还在于建立了一个可控的版本系统,这样的话你的 gem 的用户可以从中获益。这是一个很小的代价,但获得了可靠性和可预测性。

如需其他材料,RubyGems 有一个关于声明依赖关系的指南很值得一读。

在下一章中,我们将看到一个 gem 是如何受益于拥有一个更改日志,和哪些信息是值得记录的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • 当我第一次开始制作我自己的 Ruby gems 的时候,最让我沮丧的事情之一就是理解文件结构的约定。即使我可以让一...
    编程青年阅读 3,267评论 0 6
  • 发布 在第二章中, 我们简要的看了一下默认的 bundler 给我们创建的 Rakefile: 这单独的一行可以让...
    编程青年阅读 1,569评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 小时候,小时候。在我开始记事时,我已上了幼儿园。那时候,我有个死对头,他是圆滚滚。我叫软绵绵。圆滚滚不喜欢我,他总...
    苏虞阅读 786评论 1 2
  • 首先要说一下的是这篇文章是一件副产品。这是我在准备周四(3月23日20:00)的分享《法律人打开印象笔记的正确姿势...
    嵇嘉理阅读 1,992评论 1 4