ChatGPT解决这个技术问题 Extra ChatGPT

要求ruby目录中所有文件的最佳方法?

从 ruby 目录中要求所有文件的最佳方法是什么?


J
JasonSmith

怎么样:

Dir["/path/to/directory/*.rb"].each {|file| require file }

根据 Pickaxe,.rb 扩展名是可选的。从技术上讲,它改变了含义:“require 'foo.rb'”需要 foo.rb,而“require 'foo'”可能需要 foo.rb、foo.so 或 foo.dll。
不剥离扩展有一个微妙的问题。如果代码调用的其他部分需要“foo”,那么 ruby 将再次加载相同的文件,这可能会导致虚假错误。我添加了自己的答案,解释了这一点并展示了如何剥离扩展。
@Pete,这仍然是真的吗?请参阅下面的Rene's comment
这可能很明显,但值得注意的是,删除 .rb 还需要目录中的任何非 .rb 文件,这可能是不希望的。
@PeteHodgson 的建议不准确。 Ruby 的 require 不会因 .rb 扩展的存在与否而混淆。在 MRI 1.8.7-p374、2.1.5 和 2.2.0 上测试。这个都市传说来自 Rails,其中“聪明”的自动加载展示了他在旧版本中描述的行为(并且可能仍然存在)。
F
FeifanZ

如果它是相对于执行要求的文件的目录(例如,您想加载 lib 目录中的所有文件):

Dir[File.dirname(__FILE__) + '/lib/*.rb'].each {|file| require file }

编辑:根据以下评论,更新版本:

Dir[File.join(__dir__, 'lib', '*.rb')].each { |file| require file }

您还可以像这样添加所有子目录 Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }
使用 File.join 可能比对正/反斜杠做出假设更安全:Dir[File.join(File.dirname(__FILE__), 'lib', '*.rb')].each {|file| require file }
还有require_relative
如果您使用 >= ruby 2.0,则可以使用 __dir__ 而不是 File.dirname(__FILE__)
@maasha 您如何使用 require_relative 来要求目录中的所有文件?
佚名

试试 require_all gem:

http://github.com/jarmo/require_all https://rubygems.org/gems/require_all

它让您简单地:

require_all 'path/to/directory'

我需要包含我所有的 ActiveRecord 模型,require_all gem 找出了所有的依赖关系并完美地需要它们。谢谢!
@panupan 请注意,require_all 的循环依赖解析解决了您源代码中的一个问题:您拥有不需要依赖关系的 Ruby 源文件。这关闭了手术刀装载的大门,让您进行全有或全无装载。这在小型图书馆中不是问题,但这是您应该有意识地做出的决定。
用可以简单地用一行代码替换的 gem 来膨胀你的应用程序是没有意义的。这会增加您的应用程序的加载时间并长期引发更多错误。
P
Pete Hodgson
Dir[File.dirname(__FILE__) + '/../lib/*.rb'].each do |file| 
  require File.basename(file, File.extname(file))
end

如果您不剥离扩展名,那么您最终可能需要两次相同的文件(ruby 不会意识到“foo”和“foo.rb”是同一个文件)。两次要求同一个文件可能会导致虚假警告(例如“警告:已初始化常量”)。


真的是这样吗?文档说:如果一个特性的名字已经出现在 $" 中,它就不会被加载。文件名被转换为绝对路径,所以 "require 'a'; require './a'" 不会加载 a.rb 两次。ruby-doc.org/core/classes/Kernel.html#M001418
我的测试结果与 Derek 所说的相同:require "foo.rb"; require "foo"; 只会加载 foo.rb 一次。
@PeteHodgson-你能支持一下吗?
不会。Ruby 的 require 不会因 .rb 扩展的存在或不存在而混淆。在 MRI 1.8.7-p374、2.1.5 和 2.2.0 上测试。这个都市传说来自 Rails,其中“聪明”的自动加载展示了旧版本中描述的行为(并且可能仍然存在)。
m
metakungfu
Dir.glob(File.join('path', '**', '*.rb'), &method(:require))

或者,如果您想将文件范围限定为加载到特定文件夹:

Dir.glob(File.join('path', '{folder1,folder2}', '**', '*.rb'), &method(:require))

解释:

Dir.glob 将块作为参数。

方法(:要求)will return the require method.

&method(:require) 会将方法转换为块。


这是一些漂亮的代码。我喜欢没有可见块的方式。
Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) ) 消除了对平台的依赖(例如“/”或“\”)。效果很好。谢谢。
R
Ryan McGeary

最好的方法是将目录添加到加载路径,然后 require 每个文件的基本名称。这是因为您希望避免意外两次需要相同的文件——通常不是预期的行为。是否加载文件取决于 require 之前是否已经看到传递给它的路径。例如,这个简单的 irb 会话表明您可能会错误地要求和加载同一个文件两次。

$ irb
irb(main):001:0> require 'test'
=> true
irb(main):002:0> require './test'
=> true
irb(main):003:0> require './test.rb'
=> false
irb(main):004:0> require 'test'
=> false

请注意,前两行返回 true 表示两次都加载了同一个文件。使用路径时,即使路径指向同一位置,require 也不知道该文件已被需要。

相反,我们在加载路径中添加一个目录,然后需要其中每个 *.rb 文件的基本名称。

dir = "/path/to/directory"
$LOAD_PATH.unshift(dir)
Dir[File.join(dir, "*.rb")].each {|file| require File.basename(file) }

如果您不关心该文件被多次需要,或者您的意图只是加载文件的内容,那么也许应该使用 load 而不是 require。在这种情况下使用 load ,因为它更好地表达了你想要完成的事情。例如:

Dir["/path/to/directory/*.rb"].each {|file| load file }

这似乎是要求所有文件同时避免任何意外双重要求文件的最佳解决方案 - 并且应该标记为已接受的答案......
我觉得自 2009 年以来发生了一些变化。require 现在需要 ./ 并且 require_relative 意识到这些是同一个文件的路径。
s
shushugah
Dir[File.join(__dir__, "/app/**/*.rb")].each do |file|
  require file
end

这将在您的本地机器和不使用相对路径的远程(如 Heroku)上递归工作。


K
Koen.

我没有像某些答案那样连接路径,而是使用 File.expand_path

Dir[File.expand_path('importers/*.rb', File.dirname(__FILE__))].each do |file|
  require file
end

更新:

您可以执行以下操作,而不是使用 File.dirname

Dir[File.expand_path('../importers/*.rb', __FILE__)].each do |file|
  require file
end

其中 .. 去除了 __FILE__ 的文件名。


这似乎绝对是要走的路,而且是最新的答案,在尝试了所有其他方法之后,为 File.expand_path +1
我绝对更喜欢这个答案而不是接受的答案。如果您在 Rails 中,各种 Rails.root.join 答案也适用。
D
Dan Kohn

在 Rails 中,您可以:

Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }

更新:更正了@Jiggneshh Gohel 的建议以删除斜线。


由于 Rails.root 是一个 Pathname 实例,您可以在任何 Ruby 环境中执行此操作,而不仅仅是 Rails(注意 Rails.root.join('lib/ext/*.rb') 读起来更好一些)
感谢您的推荐;我编辑包括你的评论。
对 Rails.root 下的子目录使用正斜杠 (/),例如 Rails.root.join('/lib') 不会生成正确的路径。我发现这个可以正常工作:Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
@Jiggneshh Gohel 我按照您的建议删除了斜杠,谢谢。
J
Jazz

我迟到了几年,但我有点喜欢这种单线解决方案,我曾经让 rails 将所有内容都包含在 app/workers/concerns 中:

Dir[ Rails.root.join *%w(app workers concerns *) ].each{ |f| require f }


A
Aleksander

那么:require_relative *Dir['relative path']呢?


好的,但在我的例子中它不是。 '*' 将 arity 更改为 1。它作为对 require_relative 的多次调用。
'*' 将 arity 更改为 1 - 你是什么意思? require_relative *Dir['*.rb'] 工作,如果只有一个 ruby 脚本。但如果找到多个 ruby 脚本,则会得到 require_relative': wrong number of arguments (4 for 1) (ArgumentError)