144

我对 RVM 和 rbenv 的实际工作方式很感兴趣。

显然它们在不同版本的 Ruby 和 gemset 之间进行交换,但这是如何实现的呢?我原以为他们只是在更新符号链接,但在深入研究代码后(我必须承认我对 Bash 的了解是肤浅的),他们似乎做的还不止这些。

4

5 回答 5

247

简短说明: rbenv 通过挂钩到您环境的PATH. 概念很简单,但魔鬼在细节中;下面是完整的独家新闻。

首先,rbenv为所有已安装的 Ruby 版本中的所有命令(、、等)创建shims 。这个过程称为重新散列。每次安装新版本的 Ruby 或安装提供命令的 gem 时,运行以确保所有新命令都已填充。rubyirbrakegemrbenv rehash

这些垫片位于单个目录中(~/.rbenv/shims默认情况下)。要使用 rbenv,您只需将 shims 目录添加到您的前面PATH

export PATH="$HOME/.rbenv/shims:$PATH"

然后,每当您从命令行运行ruby或运行 shebang 读取的脚本#!/usr/bin/env ruby时,您的操作系统将首先找到并运行它,而不是您可能已安装~/.rbenv/shims/ruby的任何其他可执行文件。ruby

每个 shim 都是一个小型 Bash 脚本,依次运行rbenv exec。因此,在您的路径中使用 rbenv 时,irb等效于rbenv exec irb,并且ruby -e "puts 42"等效于rbenv exec ruby -e "puts 42".

rbenv exec命令确定您要使用的 Ruby 版本,然后针对该版本运行相应的命令。就是这样:

  1. 如果RBENV_VERSION设置了环境变量,它的值决定了要使用的 Ruby 版本。
  2. 如果当前工作目录有.rbenv-version文件,则其内容用于设置RBENV_VERSION环境变量。
  3. 如果当前目录中没有.rbenv-version文件,rbenv 会在每个父目录中搜索.rbenv-version文件,直到找到文件系统的根目录。如果找到,则其内容用于设置RBENV_VERSION环境变量。
  4. 如果RBENV_VERSION仍未设置,rbenv 会尝试使用~/.rbenv/version文件的内容来设置它。
  5. 如果在任何地方都没有指定版本,rbenv 假定您要使用“系统”Ruby——即如果 rbenv 不在您的路径中,将运行任何版本。

(您可以使用该命令设置特定于项目的 Ruby 版本,该命令会在当前目录rbenv local中创建一个文件。同样,该命令会修改该文件。).rbenv-versionrbenv global~/.rbenv/version

配备RBENV_VERSION环境变量,rbenv 添加~/.rbenv/versions/$RBENV_VERSION/bin到你的前面PATH,然后执行传递给rbenv exec. 瞧!

要彻底了解幕后究竟发生了什么,请尝试设置RBENV_DEBUG=1并运行 Ruby 命令。rbenv 运行的每个 Bash 命令都将写入您的终端。


现在,rbenv 只关心切换版本,但蓬勃发展的插件生态系统将帮助您完成从安装 Ruby设置环境管理“gemset”甚至自动化bundle exec.

我不太确定 IRC 支持与切换 Ruby 版本有什么关系,而 rbenv 被设计为简单易懂,不需要支持。但如果您需要帮助,只需点击几下鼠标即可获得问题跟踪器和 Twitter。

披露:我是 rbenv、ruby-build 和 rbenv-vars 的作者。

于 2012-02-23T22:20:55.003 回答
19

我写了一篇深入的文章: http: //niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/

基本区别在于 shell 环境改变的地方:

  • RVM:当你改变 Ruby 时它就改变了。
  • rbenv:当您运行 Ruby/gem 可执行文件时,它会发生变化。

此外,关于 RVM 的事情是,它涵盖的范围远远超过仅管理红宝石,它比任何其他工具都多得多(除了 RVM 和 rbenv 之外,还有其他工具:https ://twitter.com/#!/mpapis/状态/171714447910502401 )

不要忘记您在 Freenode 服务器上的“#rvm”频道中获得的即时支持。

于 2012-02-22T15:58:22.943 回答
16

所以总结一下上面的优秀答案,RVM 和 rbenv 之间的主要实际区别在于选择 Ruby 的版本。

rbenv:

rbenv 在路径的开头添加一个 shim,这是一个与 Ruby 同名的命令。当您ruby在命令行键入时,将运行 shim(因为它也称为“ruby”并且在路径中排在第一位)。shim 寻找一个环境变量或.rbenv_version文件来告诉它要委托给哪个版本的 Ruby。

RVM:

RVM 允许您通过调用rvm use. 此外,它还覆盖cd系统命令。当您cd进入包含文件的.rvmrc文件夹时,将执行文件内的代码.rvmrc。这可以用来设置一个 Ruby 版本,或者任何你喜欢的东西。

其他区别:

当然还有其他区别。RVM 具有开箱即用的 gemset,而 rbenv 只需要更多的 hacking(但不多)。两者都是问题的功能解决方案。

于 2012-03-15T15:44:46.983 回答
6
rvm system
env > before
rvm jruby # or whatever
env > after
diff after before

给你大约:

< GEM_HOME=$HOME/.gem/ruby/1.9.1
---
> GEM_HOME=$HOME/.rvm/gems/jruby-1.6.6
< GEM_PATH=$HOME/.gem/ruby/1.9.1
---
> GEM_PATH=$HOME/.rvm/gems/jruby-1.6.6:$HOME/.rvm/gems/jruby-1.6.6@global
*bunch of rvm_*
> MY_RUBY_HOME=$HOME/.rvm/rubies/jruby-1.6.6
> RUBY_VERSION=jruby-1.6.6
> IRBRC=$HOME/.rvm/rubies/jruby-1.6.6/.irbrc

它预先设置:

$HOME/.rvm/gems/jruby-1.6.6/bin:$HOME/.rvm/gems/jruby-1.6.6@global/bin

$PATH

于 2012-02-22T14:23:59.527 回答
6

主要区别似乎是何时以及如何切换 ruby​​ 。Ruby 切换:

  • 用于 RVM 手动(rvm 使用)或在更改目录期间自动
  • 每次执行 ruby​​ 命令时自动为 rbenv

RVM 依赖于cdRuby 的修改命令和手动选择rvm use。rbenv 使用所有基本 ruby​​ 命令的包装器或“垫片”作为选择 ruby​​ 的默认机制。RVM 也为 gem、rake、ruby 等基本命令行工具创建包装器。例如,它们在 CronJobs 中使用(参见http://rvm.io/integration/cron/),但它们不是切换 Ruby 版本的默认机制。

因此,这两种方法都通过覆盖命令和使用包装器来“自动”选择正确的 Ruby 版本。rvm 覆盖像 cd 这样的 shell 命令。rbenv 覆盖所有基本的 ruby​​ 命令,例如 ruby​​、irb、rake 和 gem。

于 2012-12-20T14:30:27.530 回答