我已经看到有关此错误的类似问题,但所有这些都与rails有关。我没有使用铁轨;我正在研究一个从yaml文件读取的本地rake任务,然后处理数据。我宁愿不为此安装bundler(类似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
按预期方式按键。
当我写require 'FileUtils'
时,会出现此警告。如果我写require 'fileutils'
(所有小写)警告消失。
This链接可能有助于解释行为。我认为本质上ruby认为FileUtils
和fileutils
是不同的模块,因此进口两次。然后,常量的重新声明会发出警告信息。
如果有人在这里徘徊,想要清楚地回答这个问题(在被问到两年后)。
首先,请注意Ruby中的require
不会加载模块,就像在内存中的对象FileUtils
一样。它从您的硬盘驱动器加载文件“fileutils.rb”。按惯例省略“.rb”但你可以写require 'fileutils.rb'
。
Ruby中require
的目的是只加载一次文件,而不是load
,它会在每次使用时重新加载文件。 require
避免多次加载文件的方法是记录文件名参数,如果再次传递该文件名则跳过它。
当您第一次需要文件时,Ruby会以true响应以指示它已加载。如果您再次需要相同的文件,它将返回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
)的内容。
我发现这些警告没有出现,如果我只是注释掉或删除原始代码的第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
我和特拉维斯有同样的问题,问题是我忘了使用bundle exec rake db:setup
而不是rake db:setup
。希望它可以帮助别人:)
当我列出名为“fileutils”的宝石项目有两个版本时,我解决了类似的问题
fileutils (1.1.0, default: 1.0.2)
然后我跑了
sudo gem uninstall fileutils -v 1.1.0
并解决了