rake error: "warning: already initialized constant FileUtils::OPT_TABLE"

rake error: "warning: already initialized constant FileUtils::OPT_TABLE"

我见过关于此错误的类似问题,但所有问题都与 rails 相关。我没有使用 rails;我正在处理一个本地 rake 任务,该任务从 yaml 文件中读取,然后对数据进行处理。我不想为此安装捆绑器(类似 rails 问题的解决方案建议在 bundle exec 之前加上),因为这个脚本很简单,因此不需要它。

这是简化的代码(与我正在处理的代码有相同的错误):

require 'FileUtils'
require 'yaml'

SOME_FILE = "#{Dir.pwd}/some_file.yaml"

task default: :foo

task :foo do
  bar = File.open(SOME_FILE) { |yf| YAML::load( yf ) }
  bar.each {|k,v| puts k}
end

下面是错误列表:

/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/FileUtils.rb:93: warning: already initialized constant FileUtils::OPT_TABLE
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/fileutils.rb:93: warning: previous definition of OPT_TABLE was here
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/FileUtils.rb:1272: warning: already initialized constant FileUtils::Entry_::S_IF_DOOR
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/fileutils.rb:1272: warning: previous definition of S_IF_DOOR was here
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/FileUtils.rb:1535: warning: already initialized constant FileUtils::Entry_::DIRECTORY_TERM
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/fileutils.rb:1535: warning: previous definition of DIRECTORY_TERM was here
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/FileUtils.rb:1537: warning: already initialized constant FileUtils::Entry_::SYSCASE
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/fileutils.rb:1537: warning: previous definition of SYSCASE was here
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/FileUtils.rb:1656: warning: already initialized constant FileUtils::LOW_METHODS
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/fileutils.rb:1656: warning: previous definition of LOW_METHODS was here
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/FileUtils.rb:1662: warning: already initialized constant FileUtils::METHODS
/Users/jpalmieri/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/fileutils.rb:1662: warning: previous definition of METHODS was here

脚本将 运行 尽管有警告但没问题;上面的代码会 puts 键如预期的那样,就在警告之后。

我发现如果我简单地注释掉或删除原始代码的第 1 行 (require 'FileUtils'),这些警告不会出现并且脚本运行完美。虽然我没有浏览过 Rake 的代码,但它必须已经包含 FileUtils(这是有道理的)。

为了完整起见,这是我修改后的代码(注意我删除了 require 'FileUtils' 行:

require 'yaml'

SOME_FILE = "#{Dir.pwd}/some_file.yaml"

task default: :foo

task :foo do
  bar = File.open(SOME_FILE) { |yf| YAML::load( yf ) }
  bar.each {|k,v| puts k}
end

当我写 require 'FileUtils' 时出现此警告。如果我写 require 'fileutils'(全部小写)警告消失。

This link 可能有助于解释该行为。我认为本质上 ruby 认为 FileUtilsfileutils 是不同的模块,因此将其导入两次。然后常量的重新声明给出警告信息。

我和 Travis 有同样的问题,问题是我忘记使用 bundle exec rake db:setup 而不是 rake db:setup。希望对某人有所帮助:)

想清楚地回答这个问题(被问到两年后)以防有人在这里徘徊。

首先,请注意 Ruby 中的 require 不会加载模块,就像内存中的对象 FileUtils 一样。它从您的硬盘加载文件 "fileutils.rb"。按照惯例省略了“.rb”,但您可以写成 require 'fileutils.rb'.

Ruby中的require的目的是只加载一次文件,而不是load每次使用都会重新加载文件。 require 避免多次加载文件的方法是记录文件名参数,如果再次传递该文件名则跳过它。

当您第一次需要一个文件时,Ruby 响应 true 以指示它已加载。如果您再次需要同一个文件,它将 return false 表明它已经加载:

> require 'fileutils'
=> true
> require 'fileutils'
=> false

由于 require 存储的文件名是区分大小写的,但实际文件查找不是,如果您在名称中使用大写字母,仍然会找到 fileutils.rb:

> require 'FileUtils'
=> true

但是如果你的 Ruby 程序中的某些东西已经加载了那个文件 没有 大写(在你的情况下 "yaml.rb" 可能也需要 "fileutils" ) 您将重新加载文件并可能会看到警告:

> require 'fileutils'
=> true
> require 'FileUtils'
/bin/ruby/lib/ruby/2.3.0/FileUtils.rb:96: warning: already initialized constant FileUtils::OPT_TABLE
etc.

按照约定 Ruby 文件应以小写字母命名并带有下划线,例如"my_class.rb",所以你总是使用 require 'my_class'

如果您需要使用绝对或相对路径,例如require 'special_classes/my_class'。我建议阅读 require_relative 和 Ruby 加载路径 ($LOAD_PATH).

我在列出名为 "fileutils" 的 gem 项目时解决了这个类似的问题,该项目有两个版本

fileutils (1.1.0, default: 1.0.2)

然后我运行

sudo gem uninstall fileutils -v 1.1.0

并解决了