自从几年前成为 Ruby on Rails 自由开发者以来,我做了很多项目。对于每个任务,环境设置都是非常重要的一环,因为我们要求的是高效。这也是 RVM Gemsets 非常重要的原因所在。
什么是 Gemset
Ruby RVM 允许我们为依赖项创建一个隔离的环境。如果你对 Python 非常熟悉,那么 RVM Gemset 就类似于 Python3 中的 VENV
或者 Python 2 中的 Virtualenv
使用 RVM Gemset 意味着我们可以确保避免交叉依赖项的问题,因为我们可以将给定 Ruby 版本的依赖项与其它的 Gemset 隔离开来。
因此,我们在 gems 中使用的 Ruby 默认是最后一个安装的版本。为了更清晰的了解这一点,我们来看看 RVM Gemset 的特性。
默认 ( default ) 和全局 ( global ) 的 Gemsets
当一个新的 Ruby 版本被安装时,会为这个新的版本创建两个 default
和 global
的 gemsets
$> rvm install ruby-2.4.1 ... Install of ruby-2.4.1 - #complete $> rvm gemset list gemsets for ruby-2.4.1 (found in /Users/yufei/.rvm/gems/ruby-2.4.1) => (default) global
当未明确提供使用哪个 Gemset 时,就会默认的使用 default
Gemset 。
$> rvm use 2.4.1 Using /Users/mehdi/.rvm/gems/ruby-2.4.1 $> rvm gemset list gemsets for ruby-2.4.1 (found in /Users/mehdi/.rvm/gems/ruby-2.4.1) => (default) global
而 global
gemset 是全局共享的。对于特定版本的 Ruby , 全局 gemset 可以和其它所有的 gemset 之间共享。
$> rvm use 2.4.1@global Using /Users/mehdi/.rvm/gems/ruby-2.4.1 with gemset global $> gem list *** LOCAL GEMS *** bigdecimal (default: 1.3.0) bundler-unload (1.0.2) did_you_mean (1.1.0) executable-hooks (1.3.2) gem-wrappers (1.3.0) io-console (default: 0.4.6) json (default: 2.0.2) minitest (5.10.1) net-telnet (0.1.1) openssl (default: 2.0.3) power_assert (0.4.1) psych (default: 2.2.2) rake (12.0.0) rdoc (default: 5.0.0) rubygems-bundler (1.4.4) rvm (1.11.3.9) test-unit (3.2.3) xmlrpc (0.2.1)
另一个非常重要的是, default
Gemset 是继承自 global
Gemset。这句话的意思是 default
是包含 global
Gemset 的。
$> rvm use 2.4.1 Using /Users/mehdi/.rvm/gems/ruby-2.4.1 $> gem list *** LOCAL GEMS *** bigdecimal (default: 1.3.0) bundler-unload (1.0.2) did_you_mean (1.1.0) .... rvm (1.11.3.9) test-unit (3.2.3) xmlrpc (0.2.1) $> rvm use 2.4.1 --ignore-gemsets Using /Users/mehdi/.rvm/gems/ruby-2.4.1 $> gem list *** LOCAL GEMS *** bigdecimal (default: 1.3.0) io-console (default: 0.4.6) json (default: 2.0.2) openssl (default: 2.0.3) psych (default: 2.2.2) rdoc (default: 5.0.0)
上面的代码中,添加了 --ignore-gemsets
选项则会忽略 global
gemset ( 事实上,此选项会忽略除默认gemset 之外的所有内容 )
Foobar 项目
我们将使用一个叫 Foobar
的项目来解释刚刚说的那些知识。 ( 实际上,没有比说明上述解释更好的例子了 )
我们首先假设这个项目不存在,也就是一个新的项目。然后,假设这是一个使用 Ruby 2.4.1 和 RoR5 的 SaaS 项目。
因此,第一步,就是要安装 Ruby 2.4.1,使用 rvm install
命令
$> rvm install 2.4.1 ... Install of ruby-2.4.1 - #complete
接下来就是创建 foobar gemset
$> rvm use 2.4.1 Using /Users/mehdi/.rvm/gems/ruby-2.4.1 $> rvm gemset create foobar ruby-2.4.1 #gemset created /Users/mehdi/.rvm/gems/ruby-2.4.1@foobar ruby-2.4.1 #generating foobar wrappers.............. $> rvm use 2.4.1@foobar Using /Users/mehdi/.rvm/gems/ruby-2.4.1 with gemset foobar $> gem list *** LOCAL GEMS *** bigdecimal (default: 1.3.0) bundler-unload (1.0.2) did_you_mean (1.1.0) executable-hooks (1.3.2) gem-wrappers (1.3.2, 1.3.0) io-console (default: 0.4.6) json (default: 2.0.2) minitest (5.10.1) net-telnet (0.1.1) openssl (default: 2.0.3) power_assert (0.4.1) psych (default: 2.2.2) rake (12.0.0) rdoc (default: 5.0.0) rubygems-bundler (1.4.4) rvm (1.11.3.9) test-unit (3.2.3) xmlrpc (0.2.1)
最后,在我们的 foobar gemset 中添加 bundler
gem
$> gem install bundler Fetching: bundler-1.16.1.gem (100%) Successfully installed bundler-1.16.1 Parsing documentation for bundler-1.16.1 Installing ri documentation for bundler-1.16.1 Done installing documentation for bundler after 4 seconds 1 gem installed $> gem list bundler *** LOCAL GEMS *** bundler (1.16.1) bundler-unload (1.0.2) rubygems-bundler (1.4.4)
安装好了之后,我们回到 default
gemset,看看 bundler
gem 是否在其目录下和是否可用
$> rvm use 2.4.1 Using /Users/mehdi/.rvm/gems/ruby-2.4.1 $> gem list bundler *** LOCAL GEMS *** bundler-unload (1.0.2) rubygems-bundler (1.4.4)
正如你所见,在 foobar
项目之外,bundler
并不可见。
但是,你需要注意的是,foobar 可以访问 global
gemset 中可用的所有 gem 。
总结
当你启动或加入某个 Ruby 项目( Ruby 脚本,gem,Ruby on Rails,sinatra 等等 )时,请确保创建一个新的gemset,以便为依赖项使用干净且隔离的环境
当同时处理一堆项目时,这可以节省很多时间