Мне интересно, как работают RVM и rbenv.
Очевидно, они меняются между разными версиями Ruby и gemset, но как это достигается? Я предположил, что они просто обновляют символические ссылки, но вникая в код (и я должен признать, что мои знания Bash являются поверхностными), они, похоже, делают больше, чем это.
Краткое объяснение: rbenv работает, подключаясь к вашей среде PATH
. Концепция проста, но дьявол находится в деталях; полный совок ниже.
Во-первых, rbenv создает прокладки для всех команд (ruby
, irb
, rake
, gem
и т.д.) во всех ваших установленных версиях Ruby. Этот процесс называется rehashing. Каждый раз, когда вы устанавливаете новую версию Ruby или устанавливаете драгоценный камень, который предоставляет команду, запустите rbenv rehash
, чтобы убедиться, что все новые команды отрегулированы.
Эти прокладки живут в одном каталоге (~/.rbenv/shims
по умолчанию). Чтобы использовать rbenv, вам нужно только добавить каталог прокладок в начало вашего PATH
:
export PATH="$HOME/.rbenv/shims:$PATH"
Затем в любое время, когда вы запускаете ruby
из командной строки или запускаете script, чья shebang читает #!/usr/bin/env ruby
, ваша операционная система сначала найдет ~/.rbenv/shims/ruby
и запустит ее вместо любого другого исполняемого файла ruby
возможно, установлены.
Каждая прокладка представляет собой крошечный Bash script, который, в свою очередь, запускает rbenv exec
. Итак, с rbenv на вашем пути, irb
эквивалентен rbenv exec irb
, а ruby -e "puts 42"
эквивалентен rbenv exec ruby -e "puts 42"
.
Команда rbenv exec
определяет, какую версию Ruby вы хотите использовать, затем запускает соответствующую команду для этой версии. Вот как:
RBENV_VERSION
установлена, ее значение определяет версию Ruby для использования..rbenv-version
, его содержимое используется для установки переменной среды RBENV_VERSION
..rbenv-version
, rbenv ищет каждый родительский каталог для файла .rbenv-version
, пока не попадет в корень вашей файловой системы. Если он найден, его содержимое используется для установки переменной среды RBENV_VERSION
.RBENV_VERSION
все еще не установлен, rbenv пытается установить его, используя содержимое файла ~/.rbenv/version
.(Вы можете установить версию Ruby для конкретного проекта с помощью команды rbenv local
, которая создает в текущем каталоге файл .rbenv-version
. Аналогично, команда rbenv global
изменяет файл ~/.rbenv/version
.)
Вооруженный переменной окружения RBENV_VERSION
, rbenv добавляет ~/.rbenv/versions/$RBENV_VERSION/bin
в начало вашего PATH
, затем выполняет команду и аргументы, переданные в rbenv exec
. Вуаля!
Подробно посмотрите, что происходит под капотом, попробуйте установить RBENV_DEBUG=1
и запустить команду Ruby. Каждая команда Bash, запускаемая rbenv, будет записана на ваш терминал.
Теперь rbenv просто касается переключения версий, но процветающая экосистема плагинов поможет вам сделать все, начиная с установки Ruby до настройка среды, управление "gemsets" и даже автоматизация bundle exec
.
Я не совсем уверен, что поддержка IRC связана с переключением версий Ruby, и rbenv разработан, чтобы быть простым и понятным, чтобы не требовать поддержки. Но если вам когда-нибудь понадобится помощь, трекер и Twitter будут всего в нескольких кликах.
Раскрытие информации: Я являюсь автором rbenv, ruby-build и rbenv-vars.
Я написал углубленную статью: http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/
Основное отличие заключается в том, что среда оболочки изменяется:
Кроме того, дело в RVM заключается в том, что он охватывает намного больше, чем просто управление Rubies, у него намного больше, чем у любого другого инструмента (кроме RVM и rbenv есть другие: https://twitter.com/#!/mpapis/status/171714447910502401)
Не забывайте о мгновенной поддержке, которую вы получаете на IRC в канале "#rvm" на серверах Freenode.
Итак, чтобы обобщить превосходные ответы выше, основная практическая разница между RVM и rbenv заключается в том, когда выбрана версия Ruby.
rbenv:
rbenv добавляет прокладку к началу вашего пути, команду с тем же именем, что и Ruby. Когда вы введете ruby
в командной строке, вместо этого выполняется прокладка (потому что она также называется "ruby" и на первом идет по пути). Прокладка ищет переменную окружения или файл .rbenv_version
, чтобы сообщить, какую версию Ruby нужно делегировать.
RVM:
RVM позволяет вам устанавливать версию Ruby напрямую, вызывая rvm use
. Кроме того, он также отменяет системную команду cd
. Когда вы cd
в папку, содержащую файл .rvmrc
, выполняется код внутри файла .rvmrc
. Это можно использовать для установки версии Ruby или всего, что вам нравится.
Другие отличия:
Конечно, есть и другие отличия. RVM имеет gemsets из коробки, в то время как rbenv требует только немного большего взлома (но не много). Оба являются функциональными решениями проблемы.
Основное различие, по-видимому, когда и как рубин переключается. Рубин переключается:
RVM полагается на измененную команду cd
и ручной выбор Ruby на rvm use
. rbenv использует обертки или "прокладки" для всех основных команд ruby в качестве механизма по умолчанию для выбора рубина. RVM создает обертки для базовых инструментов командной строки, таких как gem, rake, ruby. Они используются, например, в CronJobs (см. http://rvm.io/integration/cron/), но они не являются механизмом по умолчанию для переключения версии Ruby.
Таким образом, оба метода выбирают "автоматически" правильную версию Ruby путем перезаписи команд и использования оберток. rvm переопределяет команды оболочки, такие как cd. rbenv переопределяет все основные рубиновые команды, такие как ruby, irb, rake и gem.
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
to $PATH