为什么我会在`bundle exec ruby​​ [file]中得到NameError,因为必要的gem在Gemfile中?

时间:2016-07-04 18:43:48

标签: ruby rubygems bundler gemfile

我正在做一些搞乱,试图更好地了解Bundler的工作原理。我的工作目录中只有三个文件:

Gemfile Gemfile.lock test.rb

所有Gemfile都是gem "slop"test.rb如下所示:

puts Slop.parse

当我运行bundle exec test.rb时,由于没有NameError声明,我收到了require

[ec2-user@xx my_app]$ bundle exec ruby test.rb
test.rb:1:in `<main>': uninitialized constant Slop (NameError)

但如果我运行bundle console,Bundler会正确加载gem,我可以从控制台运行Slop.parse,而无需显式输入require "slop"

[ec2-user@xx my_app]$ bundle console
irb(main):001:0> Slop.parse
=> #<Slop::Result:0x00000001339838...

那我错过了什么?我的印象是,由于我require: false中没有Gemfile,因此当我运行Slop时应该加载bundle exec ruby test.rb我不需要文件中的require "slop"行。

3 个答案:

答案 0 :(得分:3)

您需要配置bundler以要求Gemfile上的所有宝石:

require 'rubygems'
require 'bundler/setup'
Bundler.require(:default)

查看http://bundler.io/v1.12/bundler_setup.html

上的文档

答案 1 :(得分:0)

  

我的印象是,因为我没有require: false   当我运行bundle exec ruby​​ test.rb时,应该加载我的Gemfile,Slop   我不需要在文件中放置require“slop”行。

bundler docs说:

  

在项目根目录中的Gemfile中指定依赖项:

source 'https://rubygems.org'

gem 'nokogiri'   #<======HERE
  

在您的应用内部,加载捆绑的环境:

require 'rubygems' 
require 'bundler/setup'

# require your gems as usual 
require 'nokogiri'   #<========AND HERE

至于此:

  

我的印象是,因为我没有require: false   当我运行bundle exec ruby​​ test.rb时,应该加载我的Gemfile,Slop   我不需要在文件中放置require“slop”行。

捆绑者文档在这一点上非常糟糕。据我所知,:require => false是一个Rails特定的东西,用于减少项目启动时的加载时间。 在rails应用 中,指定require: false表示在手动需要gem之前不会加载gem。如果你没有指定:require => false,那么gem将自动加载 - 但这是因为rails代码被编写为执行自动加载。您的应用没有执行类似功能的代码。

编辑:测试时出错。所以这就是它的工作方式: 在非rails应用 中,例如在你的test.rb中,如果你想自动要求Gemfile中指定的所有gem,你需要写:

Bundler.require :default

Bundler docs在细则中提到:

  

指定:require => false以防止捆绑包需要gem,   但仍然安装它并保持依赖关系。

gem 'rspec', :require => false
gem 'sqlite3'
     

为了在Gemfile中要求宝石,您需要在应用程序中调用Bundler.require

我不确定为什么这个要求只与require: false一起提及,而不是在开头时说明。

并且,如果您指定:

,则在您的Gemfile中
gem 'slop', :require => false

(以及test.rb中的Bundler.require :default),那么你还必须在test.rb中明确要求slop gem:

 require 'slop'  

换句话说,Bundler.require :default会自动要求Gemfile中的所有宝石,但标有require: false的宝石除外。对于标有require: false的宝石,您必须在应用中手动编写require 'gem_name'

因此,neydroid发布了正确的解决方案。

*在你的Gemfile中,你可以在组中嵌套宝石,这会影响Bundler.require()的工作方式。请参阅Bundler docs on groups

答案 2 :(得分:-2)

你应该添加要求&#34; slop&#34;在你的test.rb里面