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

Why do I get NameError with `bundle exec ruby [file]` given that the necessary gem is in Gemfile?

我正在做一些乱七八糟的事情,试图更好地理解捆绑器的工作原理。我的工作目录中只有三个文件:

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...

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

您需要像这样配置捆绑器以要求 Gemfile 上的所有 gem:

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

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

上的文档

I was under the impression that since I don't have require: false in my Gemfile, Slop should be loaded when I run bundle exec ruby test.rb and I shouldn't need to put the require "slop" line in the file.

bundler docs 说:

Specify your dependencies in a Gemfile in your project's root:

source 'https://rubygems.org'

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

Inside your app, load up the bundled environment:

require 'rubygems' 
require 'bundler/setup'

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

至于这个:

I was under the impression that since I don't have require: false in my Gemfile, Slop should be loaded when I run bundle exec ruby test.rb and I shouldn't need to put the require "slop" line in the file.

捆绑文档在这一点上很糟糕。据我所知,:require => false 是 Rails 特定的东西,用于减少项目启动时的加载时间。 在 rails 应用程序 中,指定 require: false 意味着 gem 将不会加载,直到您手动要求 gem。如果您不指定 :require => false,那么 gem 将被自动加载——但那是因为 rails 代码被编写来执行自动加载。您的应用没有执行类似功能的代码。

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

Bundler.require :default

Bundler docs 在细则中提到:

Specify :require => false to prevent bundler from requiring the gem, but still install it and maintain dependencies.

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

In order to require gems in your Gemfile, you will need to call Bundler.require in your application.

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

并且,如果您在 Gemfile 中指定:

gem 'slop', :require => false

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

 require 'slop'  

换句话说,Bundler.require :default 自动需要 Gemfile 中的所有 gem,除了标有 require: false 的 gem。对于标有 require: false 的 gem,您必须在应用中手动写入 require 'gem_name'

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


* 在您的 Gemfile 中,您可以将 gem 嵌套在组中,这会影响 Bundler.require() 的工作方式。见 Bundler docs on groups.

您应该在 test.rb

中添加要求 "slop"