儘管 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 保持同步。