尽管 Internet Relay Chat、论坛和版本控制工具(如 Git 和 Github)令分布式开发变得十分简单,可是重建另外一个开发人员的环境将会十分困难。在一个新的开发机器上支持现有代码体,须要至少匹配初始编码人员的部分(也有多是所有)堆栈,或是匹配加强应用程序所必需的软件组件。堆栈可能要求使用某种操做系统(好比 UNIX®、Linux®、Mac OS 或 Windows®);特定的操做系统版本(Ubuntu 10 或 11?Mac OS X 10.6 Snow Leopard 或 10.7 Lion?);内置和辅助的系统库与标头文件的最小集合;守护程序 (daemon) 和服务(MySQL 或 PostgreSQL?)的配套设施;固然,还包括各类特定于语言的资源,包括从编译器到特定补丁级别的配套开源代码。git
在最坏状况下,一些代码被锁定,或依赖每层堆栈的特定修改,甚至可能依赖特定的硬件。更理想的状况下,堆栈中的标准和抽象也会简化可移植性。可移植的操做系统接口 (POSIX) 合规性就是一种有用的标准:这样,支持 POSIX 标准的各类系统将提供相同的软件接口并生成相同的结果。Ruby 之类的解释型语言可以支持抽象,由于不须要进行编译,代码能够(能够想象)在任何具有解释器的平台上运行。github
也就是说,即便是使用 Perl、PHP 和 Ruby 等解释型语言编写的应用程序代码,都要求在必定程度上适应新的机器。事实上,Ruby 一般要求进行至关的设置工做,很大程度上是由于 Ruby 在持续不断地快速演进,并被推向更多变化的计算环境中。那就是说,在撰写本文之际,该语言有两个流行版本在供使用,至少 5 种 Ruby 解释器基于三种不一样的计算机语言,而每一个解释器又有几个不一样的版本,更不要说还存在成千上万种第三方库:web
- Ruby 版本 1.8 仍然在使用中,而 Ruby 版本 1.9 在最近的编码工做中更受青睐。
- Ruby 解释器包括 Matz 的 Ruby Interpreter(MRI:采用
C
编写,以 Ruby 的建立者命名,即日本计算机科学家 Yukihiro Matz Matsumoto);JRuby(采用 Java™ 语言编写,由 Java Virtual Machine [JVM] 驱动);Rubinius(采用 Ruby 编写,在 C++
字节码虚拟机 [VM] 顶上运行);Ruby Enterprise Edition([REE] Ruby 代码的一个分支并进行了加强,能够提高性能并下降内存消耗);以及 MagLev(一种快速且稳定的 64 位 Ruby 实现,基于 VMware 的 GemStone/S 3.1 VM)(参见 参考资料 中的连接)。全部解释器都是开源的。每一个解释器都有本身的优势,具体要使用哪一种解决方案取决于应用程序和开发人员的偏好。
- 根据 RubyGems.org(已提供的 Ruby 代码的官方库),目前共有 41780 个 gem 实例可用。
并非全部 Ruby 解释器均可以互相替代,这令状况变得更复杂。虽然不一样实现之间发生的大部分代码迁移不会出现问题,可是不能保证(在全部状况下)某个解释器会产生与另外一个解释器相同的结果。考虑到如此多的种类以及对结果进行比较的须要,Ruby 开发人员须要迅速访问多个堆栈(正如使用 C
语言进行编码的开发人员同样),可是维护不一样的 Ruby 开发环境可不像在计算机上使用两个不一样 C
编译器那么简单。Shell 环境变量(包括 PATH、GEM_PATH 和 GEM_HOME)有助于将环境分离开来,可是要在两个堆栈之间实现一致、清晰、正确的划分,须要进行大量的工做并遵循严格的纪律。shell
现在,Ruby 开发人员拥有了一个近乎 神奇的 替代选择:Ruby Version Manager (RVM),它的建立者是 Wayne E. Seguin(参见 参考资料 中的连接)。json
Ruby Version Manager 简介
RVM 提供了一些重要的特性:canvas
- RVM 目前可构建超过 35 种实现。经过一条命令就能够下载、构建和安装任意 Ruby 解释器。
- 它建立和管理任意数量的 Ruby 环境,其中每一个环境提供单独的 Ruby 解释器。所以,一个项目可使用 JRuby,而在同一台计算机上开发的另外一个项目则能够指定最新的 MRI。
- 此外,每一个环境能够拥有任意数量的分散 gem 集合。RVM 将每一个集合适当地称为 gemset。您能够有一个与 JRuby 关联的名为
auto_parts_store
的 gemset,以及一个与 MRI 版本 1.9.3 关联的名为 auto_parts_store
的彻底不一样的 gemset。每一个 gemset 在解释器上下文中必须使用一个唯一名称。
- 解释器与 gemset 的结合(提供运行 Ruby 代码和库代码主体的引擎)可经过
interpreter@gemset
符号轻松引用,其中,interpreter
是一个已知解释器的名称,而 gemset
是现有 gemset 的名称。例如,1.8.7p302@acme
指的是面向该语言的 1.8.7 版本的 Ruby MRI 补丁级别 302,以及面向 Acme 网站的 gem 集合。gemset 可使用任意名称。各个解释器的名称由 RVM 提供。
- 在不一样环境之间切换很是简单。您须要键入如下命令:
rvm interpreter@gemset
。
- 一般,在您的主目录中,每一个环境都是自包含的和筒仓式 (siloed) 的。事实上,整个 RVM 系统都位于您的主目录中,确保另外一个用户没法强制改写或破坏您已经集合的内容,相似地,您也没法破坏其余用户已经集合的内容。(您也能够集中安装 RVM,可是这种作法不太常见)。
- 您能够对其中一个、一些或全部环境运行应用程序的测试套件。在本地运行 MRI,可是在服务器上使用 REE。使用 RVM 对二者测试代码,而后再正式使用这些修改。
RVM 容许您快速试用代码组合,从而能够保持应用程序的稳定和与时俱进。若是发布了一个新的 MRI,您能够在 RVM 中构建它,建立一个新的环境,运行测试,若是一切顺利的话就可使用这个新的 MRI 了。缓存
回页首ruby
入门
RVM 的安装很是简单。只须要使用一条命令并对您的 shell 启动脚本稍做更改便可。bash
然而,RVM 须要知足一些先决条件。在继续以前,请检查您的系统,并确保已经在本地安装了 bash
、git
、tar
、curl
、gunzip
和 bunzip2
实用程序。此外,您的系统必须具有 Readline
、IConv
、zLib
、OpenSSL
和 Autoconf
包来构建 Ruby 解释器。您必须用 Bash shell 来安装 RVM,可是能够在安装 RVM 后将其用于 Z sehll 版本 4.3.5 或更高版本。自动更新 RVM 时须要使用 git
,稍后将介绍这一内容。
若是您的系统缺乏上述列出的全部包,您能够经过一个包管理器快速安装,如对各类 Linux 发行版使用 Advanced Packaging Tool,或对 Mac OS X 使用 brew
。您还必须具有 GNU C
编译器来构建应用程序。
准备好系统后,转到一个 shell 提示符并输入(或复制并粘贴)如下命令:
$ bash < <(curl http://rvm.beginrescueend.com/releases/rvm-install-head)
注意:两个小于号 (<
) 之间有一个空格。特殊的 Bash 语法 <(...)
运行圆括号中的命令并将输出保存到一个临时文件中。第一个 <
是典型的输入重定向。所以,该命令运行 bash
,并从由 curl
建立的临时文件中提供输入。将序列看做是运行一个 shell 脚本,尽管它存储在一个远程服务器中。
准备好系统以后,转到一个 Shell 提示符并输入(或复制并粘贴)命令。
$ curl -L https://get.rvm.io | bash -s stable
该命令使用 git
在您的主目录中克隆并建立一个本地 RVM 实例。查看 $HOME/.rvm 下的 bin 子目录自己包含 rvm
实用程序,而 rubies 是 Ruby 解释器的最终目录。您会发现 RVM 将根据解释器的类型、版本和 gemset 将累积的软件组织到一个可预测的层次结构中。
完成脚本安装后,您必须编辑 shell 的 dot 或启动文件,以便在新 shell 启动时可以加载 RVM shell 函数。一般状况下,该行为:
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
必须是 . 文件的最后一行。若是使用 bash
,将该行代码附加到 $HOME/.bashrc 文件的末尾。要使更改生效,必须启动一个新 shell 或输入source $HOME/.bashrc
从新加载文件。
回页首
选择任意 Ruby 版本
如今,RVM 已安装完毕,接下来要下载、构建和安装一个或多个 Ruby 解释器。有许多 Ruby 版本可用:计数语言版本、补丁级别,以及基础实现。您可使用 rvm list known
命令列出全部已知的版本,如 清单 1 所示。
清单 1. 列出全部已知的 Ruby 解释器版本
$ rvm list known
# MRI Rubies
[ruby-]1.8.6[-p420]
[ruby-]1.8.6-head
[ruby-]1.8.7[-p352]
[ruby-]1.8.7-head
[ruby-]1.9.1-p378
[ruby-]1.9.1[-p431]
[ruby-]1.9.1-head
[ruby-]1.9.2-p180
[ruby-]1.9.2[-p290]
[ruby-]1.9.2-head
[ruby-]1.9.3-preview1
[ruby-]1.9.3-rc1
[ruby-]1.9.3[-p0]
[ruby-]1.9.3-head
ruby-head
# GoRuby
goruby
# JRuby
jruby-1.2.0
jruby-1.3.1
jruby-1.4.0
jruby-1.6.1
jruby-1.6.2
jruby-1.6.3
jruby-1.6.4
jruby[-1.6.5]
jruby-head
# Rubinius
rbx-1.0.1
rbx-1.1.1
rbx-1.2.3
rbx-1.2.4
rbx[-head]
rbx-2.0.0pre
# Ruby Enterprise Edition
ree-1.8.6
ree[-1.8.7][-2011.03]
ree-1.8.6-head
ree-1.8.7-head
# Kiji
kiji
# MagLev
maglev[-head]
maglev-1.0.0
# Mac OS X Snow Leopard Only
macruby[-0.10]
macruby-nightly
macruby-head
# IronRuby -- Not implemented yet.
ironruby-0.9.3
ironruby-1.0-rc2
ironruby-head
针对 Ruby 1.8.7 的补丁级别 352 MRI 为 Ruby 和 Rails 的开发提供了良好的基础。让咱们首先安装该补丁。
输入 rvm install
和引擎名称 ruby-1.8.7-p352
。您也能够输入 rvm install 1.8.7
。在方括号 ([]
) 中出现的部分解释器名称是可选的,所以 rvm install 1.8.7
与 rvm install ruby-1.8.7-p352
是同样的。一般,若是只指定了一个版本,RVM 将安装该版本的最新代码。
安装好解释器后,RVM 将为您下载并构建代码。清单 2 显示了代码。
清单 2. 构建解释器
$ rvm install 1.8.7
Installing Ruby from source to: /Users/strike/.rvm/rubies/ruby-1.8.7-p352, this
may take a while depending on your cpu(s)...
ruby-1.8.7-p352 - #fetching
ruby-1.8.7-p352 - #downloading ruby-1.8.7-p352,
this may take a while depending on your connection...
ruby-1.8.7-p352 - #extracting ruby-1.8.7-p352 to /Users/strike/.rvm/src/ruby-1.8.7-p352
ruby-1.8.7-p352 - #extracted to /Users/strike/.rvm/src/ruby-1.8.7-p352
Applying patch 'stdout-rouge-fix'
located at /Users/strike/.rvm/patches/ruby/1.8.7/stdout-rouge-fix.patch)
ruby-1.8.7-p352 - #configuring
ruby-1.8.7-p352 - #compiling
ruby-1.8.7-p352 - #installing
Retrieving rubygems-1.8.10
Extracting rubygems-1.8.10 ...
Removing old Rubygems files...
Installing rubygems-1.8.10 for ruby-1.8.7-p352 ...
Installation of rubygems completed successfully.
ruby-1.8.7-p352 - adjusting #shebangs for (gem irb erb ri rdoc testrb rake).
ruby-1.8.7-p352 - #importing default gemsets (/Users/strike/.rvm/gemsets/)
Install of ruby-1.8.7-p352 - #complete
要切换到刚刚安装的 1.8.7 解释器,输入 rvm 1.8.7
。要列出当前环境的具体内容,输入 rvm info
。清单 3 显示了代码。
清单 3. 切换到 1.8.7 解释器
$ rvm 1.8.7
$ rvm info
rvm:
version: "rvm 1.10.0-pre by Wayne E. Seguin
(wayneeseguin@gmail.com) [https://rvm.beginrescueend.com/]"
ruby:
interpreter: "ruby"
version: "1.8.7"
date: "2011-06-30"
platform: "i686-darwin11.2.0"
patchlevel: "2011-06-30 patchlevel 352"
full_version: "ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-darwin11.2.0]"
homes:
gem: "/Users/strike/.rvm/gems/ruby-1.8.7-p352"
ruby: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352"
binaries:
ruby: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352/bin/ruby"
irb: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352/bin/irb"
gem: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352/bin/gem"
rake: "/Users/strike/.rvm/gems/ruby-1.8.7-p352/bin/rake"
environment:
PATH: "/Users/strike/.rvm/gems/ruby-1.8.7-p352/bin:
/Users/strike/.rvm/gems/ruby-1.8.7-p352@global/bin:
/Users/strike/.rvm/rubies/ruby-1.8.7-p352/bin:/Users/strike/.rvm/bin:
/Users/strike/.gem/ruby/1.8.7/bin:/Users/strike/.ruby_versions/ruby-1.8.7-p174/bin:
/Users/strike/bin/rds:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11/bin"
GEM_HOME: "/Users/strike/.rvm/gems/ruby-1.8.7-p352"
GEM_PATH: "/Users/strike/.rvm/gems/ruby-1.8.7-p352:
/Users/strike/.rvm/gems/ruby-1.8.7-p352@global"
MY_RUBY_HOME: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352"
IRBRC: "/Users/strike/.rvm/rubies/ruby-1.8.7-p352/.irbrc"
RUBYOPT: ""
gemset: ""
最重要的信息位于 interpreter
、version
、patchlevel
和 gemset
行,这些信息分别反映了解释器的类型、语言版本、修改,以及当前的 gemset。若是切换到一个新的环境,例如,切换到 ree@auto_parts_store
,这些代码行也将发生相应的变化。事实上,所显示的大多数信息都将在每次切换环境时发生变化。此外,RVM 将自动修改 shell 设置和变量,为每一个 RVM 环境建立一个岛 (island)。注意,PATH 已经更改成指向新的 Ruby。输入 which ruby
进行确认。
$ which ruby
/Users/strike/.rvm/rubies/ruby-1.8.7-p352/bin/ruby
能够看到,路径中的第一个可执行的 Ruby 就是刚刚安装的那个。
要安装不一样的 Ruby 解释器,再次运行 rvm install
来指定一个不一样的名称。在任什么时候间输入 rvm list
均可以发现您在本地安装的 ruby。
$ rvm list
jruby-1.6.4 [ x86_64 ]
ree-1.8.7-2009.10 [ i686 ]
ree-1.8.7-2010.02 [ i686 ]
ruby-1.8.7-p334 [ i686 ]
=> ruby-1.8.7-p352 [ i686 ]
ruby-1.9.2-p0 [ x86_64 ]
ruby-1.9.2-p290 [ x86_64 ]
输出中的箭头表示当前正在使用的 Ruby 解释器。
相似地,若是但愿了解当前环境中定义的全部 gemset 的名称,输入 rvm gemset list
。一样,其中的箭头一样表示当前使用的 gemset。
$ rvm gemset list
gemsets for ruby-1.8.7-p352 (found in /Users/strike/.rvm/gems/ruby-1.8.7-p352)
brewster
canvas-src
global
=> miner
moms
tech
在这些 gemset 中,名为 global
的 gemset 比较特殊。正如 Wayne Seguin 所解释的,“RVM 为每一个 Ruby 解释器提供了一个 global
gemset。针对给定 Ruby 安装到 global
gemset 的 gem 可用于全部其余与该 Ruby 相关的 gemset。这种方法容许全部项目针对特定 Ruby 解释器安装共享相同的 gem”。让咱们看看如何建立、删除、扩展并切换到不一样的 gemset。
回页首
管理 gemset
RVM 容许您从一个解释器切换到另外一个解释器。您如今能够在一个目录中根据 Ruby 版本 1.9.2 的特性和语法开发一个新的代码,并在另外一个目录中维护较旧的 1.8.7 的代码库,这两个目录都在同一个计算机中。您甚至还能够在所选的任意 Ruby 版本中运行单一代码库。
下一步是使用独立的 gemset 管理项目的库依赖关系。
为了对此进行演示,假设目录 web-1.8.7 包含一个基于 Rails 3.1 和 Ruby 1.8.7 的 Rails 应用程序,而目录 daemon-1.9.2 是一个使用 Ruby 编写的系统守护程序,基于版本 1.9.2(您不须要将版本号放到目录名中;这里使用了显式命名来最小化混淆)。为每一个代码库提供各自的 gemset,看看如何填充每一个代码库。
要切换到 1.8.7,输入 rvm 1.8.7
。输入 rvm gemset create web
以建立一个名为 Web 的新 gemset,如 清单 4 所示。
清单 4. 建立并选择一个 gemset
$ cd web-1.8.7
$ rvm 1.8.7
$ rvm gemset create web
$ rvm gemset list
brewster
canvas-src
global
=> miner
moms
tech
web
$ rvm gemset use web
$ rvm gemset list
brewster
canvas-src
global
miner
moms
tech
web
=> web
$ rvm info
ruby:
interpreter: "ruby"
version: "1.8.7"
...
patchlevel: "2011-06-30 patchlevel 352"
...
gemset: "web"
rvm gemset create
将制造一个新的 gemset,可是不会将它变为最新的、活动的 gemset。使用 rvm gemset use
切换到一个特定的 gemset。您可使用 rvm info
命令在任什么时候间检查或确认本身的状态。
新的 gemset 激活后,有关 gem 安装的任何命令都将只影响该 gemset。例如,最多见的 gem install
命令将添加一个 gem 列表。当 gemset 激活后,gem 将不会安装到系统 gem 缓存中,而是安装到 gemset 本身的缓存中,如 清单 5 所示。
清单 5. 将 gem 安装到 gemset
$ rvm gemset use style --create
$ gem list
$ gem install rails
Fetching: multi_json-1.0.4.gem (100%)
Fetching: activesupport-3.1.3.gem (100%)
Fetching: builder-3.0.0.gem (100%)
Fetching: i18n-0.6.0.gem (100%)
Fetching: activemodel-3.1.3.gem (100%)
...
Successfully installed rails-3.1.3
29 gems installed
$ gem list
*** LOCAL GEMS ***
actionmailer (3.1.3)
actionpack (3.1.3)
activemodel (3.1.3)
activerecord (3.1.3)
activeresource (3.1.3)
activesupport (3.1.3)
arel (2.2.1)
builder (3.0.0)
bundler (1.0.21)
erubis (2.7.0)
hike (1.2.1)
i18n (0.6.0)
json (1.6.3)
mail (2.3.0)
mime-types (1.17.2)
multi_json (1.0.4)
polyglot (0.3.3)
rack (1.3.5)
rack-cache (1.1)
rack-mount (0.8.3)
rack-ssl (1.3.2)
rack-test (0.6.1)
rails (3.1.3)
railties (3.1.3)
rake (0.8.7)
rdoc (3.12)
sprockets (2.0.3)
thor (0.14.6)
tilt (1.3.3)
treetop (1.4.10)
tzinfo (0.3.31)
要验证 gem 是否密封在 gemset 中,切换到另外一个 gemset 并从新运行 gem list
。切换回来并再次运行命令。
与 gem
命令相似,bundler
命令也安装 gem,可是是从一个名为 Gemfile 的清单文件 (manifest) 安装的。若是在一个 gemset 上下文中运行bundler
,gem 将被单独添加到该集合中。结合 RVM 和 bundler
能够在两个 Rails 项目之间轻松切换。
若是须要从头开始从新建立 gemset,可使用 rvm gemset empty someset
一举删除全部内容。因为 rvm empty
具备破坏性和不可逆性,所以 RVM 将提示要求确认。输入 yes
以继续:
$ rvm gemset empty someset
WARN: Are you SURE you wish to remove the installed gems for
gemset 'ruby-1.8.7-p352@someset' (/Users/strike/.rvm/gems/ruby-1.8.7-p352@someset)?
(anything other than 'yes' will cancel) > yes
$ rvm gemset delete someset
WARN: Are you SURE you wish to remove the entire gemset
directory 'someset' (/Users/strike/.rvm/gems/ruby-1.8.7-p352@someset)?
(anything other than 'yes' will cancel) > yes
代码行 rvm gemset delete someset
将彻底删除 gemset someset
。这也要求显示一个提示。
您能够经过输入 rvm help
找到 RVM 命令的完整列表,或参考 RVM 网站中的文档和提示。
回页首
其余提示
RVM 很是易于掌握,可是它具备许多普遍和精深的特性,能够令开发工做变得垂手可得。本文仅仅介绍了在实用程序中发现的其中一些 gem。
- 理想状况下,您的系统具有这里列出的全部实用程序和包,做为您尝试构建 Ruby 以前的先决条件。然而,若是您没法安装或构建这些包中的任意一者(好比,由于您不具有足够的权限来自定义本身的计算机),RVM 则提供另外一种选择。您能够在本身的 $HOME/.rvm 目录中逐一安装 5 个库(
Readline
、IConv
、zLib
、OpenSSL
和 Autoconf
)做为私有副本并照常使用 RVM。
- RVM 自己常常会发生修改。您能够经过使用
rvm get latest
命令自动更新 RVM 软件。get latest
命令将使用最新、最稳定的实用程序版本刷新您的本地代码。若是但愿尝试 RVM 的高级特性,输入 rvm get head
便可安装最新版本。
- 若是您常常建立 gemset,您可能但愿有一种快捷方式,经过一个步骤就可建立和使用 gemset。
rvm gemset use xyz --create
命令能够建立 gemset xyz
(若是不存在的话)并当即切换到该 gemset。
- 若是对某个项目使用特定的环境,能够向项目的 root 添加一个特殊的 dot 文件,从而在每次进入项目目录时自动切换到该环境。只需建立一个 .rvmrc 文件并编写命令行中经常使用的 RVM 命令,就可切换到您但愿的环境。例如,若是将
rvm ree@health
放到文件中,在将目录更改成项目的任何文件夹时,RVM 将自动设置正确的解释器和 gemset。
- 若是将 .rvmrc 和 Gemfile 选为源代码控制,下一个接手您的工做的开发人员能够快速从新生成全部开发所必需的需求。
回页首
RVM 是 Ruby 开发人员的最佳拍档
RVM 无疑正在快速成为一种必不可少的工具。RVM 可能会取消虚拟机或做为替代或额外 Ruby 开发环境而维护的一小部份内容。更棒的是,随着 Ruby 的演进,您能够与 RVM 保持同步。