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


Answers:


462

怎么样:

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

18
根据镐,.rb扩展名是可选的。从技术上讲,它更改了含义:“ require'foo.rb'”需要foo.rb,而“ require'foo'”可能需要foo.rb,foo.so或foo.dll。
— 山姆·斯托克斯

28
不删除扩展名有一个微妙的陷阱。如果代码调用的其他部分需要'foo',那么ruby将再次加载同一文件,这可能导致虚假错误。我添加了自己的答案,它解释了这一点,并说明了如何删除扩展名。
— 皮特·霍奇森

4
@Pete,这仍然是真的吗?请参阅下面的Rene评论。
— 安德烈斯·里奥弗里奥

5
这可能很明显,但是值得注意的是,删除.rb也将需要dir中的所有非.rb文件,这可能是不希望的。
— user2398029 2012年

10
@PeteHodgson的建议不正确。Ruby的require存在与否并不引起混淆.rb。在MRI 1.8.7-p374、2.1.5和2.2.0上进行了测试。这个城市传说来自Rails,“聪明”的自动加载展示了他在较旧版本中描述的行为(并且可能仍然展示出来)。
— sheldonh 2015年

345

如果是相对于需要执行此操作的文件的目录(例如,要加载lib目录中的所有文件):

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

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

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

14
您也可以像这样添加所有子目录Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }
— jspooner 2012年

62
使用File.join而不是对正斜线/反斜线进行假设可能更安全:Dir[File.join(File.dirname(__FILE__), 'lib', '*.rb')].each {|file| require file }
— 克里斯(Chris)

6
还有require_relative
— maasha

30
如果您使用> = ruby​​ 2.0,则可以使用__dir__代替File.dirname(__FILE__)。
— Christian Bankester 2014年

3
@maasha如何require_relative用来要求目录中的所有文件?
— David Moles

101

尝试require_all gem:

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

它可以让您简单地:

require_all 'path/to/directory'

我需要包括我所有的ActiveRecord模型,require_all gem找出所有依赖项并完美地需要它们。谢谢!
— panupan 2011年

2
@panupan请注意,require_all循环依赖关系解析可解决您的源代码中的问题:您有不需要它们依赖关系的Ruby源文件。这会在手术刀装载时关上门,使您无法进行全部或全部装载。在小型图书馆中这不是问题,但是这是您应该自觉做出的决定。
— sheldonh 2015年

可以用一行代码替换掉的gem膨胀您的应用程序是没有意义的。从长远来看,这会增加应用程序的加载时间并引发更多错误。
— Pere Joan Martorell,

52
Dir[File.dirname(__FILE__) + '/../lib/*.rb'].each do |file| 
  require File.basename(file, File.extname(file))
end

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


11
真的是这样吗?文档说:如果某个功能的名称已经出现在$“中,则该功能将不会被加载。文件名将转换为绝对路径,因此,” require'a“; require'./a'“不会两次加载a.rb。ruby-doc.org/core/classes/Kernel.html#M001418
— Derek

13
我的测试显示了与德里克所说的相同:require "foo.rb"; require "foo";将foo.rb仅加载一次。
— Rene Saarsoo 2011年

@ PeteHodgson-您能备份吗?
— Yarin 2013年

4
号Ruby的require不被的存在或不存在混淆.rb扩展。经MRI 1.8.7-p374、2.1.5和2.2.0测试。这个城市传说来自Rails,“聪明”的自动加载表现出旧版本中描述的行为(并且可能仍然表现出来)。
— sheldonh 2015年

45
Dir.glob(File.join('path', '**', '*.rb'), &method(:require))

或者,如果要确定文件范围以加载到特定文件夹,请执行以下操作:

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

说明:

Dir.glob以块作为参数。

method(:require)将返回require方法。

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


2
这是一些漂亮的代码。我喜欢没有可见的障碍物。
— Nate Symer 2014年

1
Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) )消除了对平台的依赖(例如“ /”或“ \”)。效果很好。谢谢。
— 伊万·布莱克

30

最好的方法是将目录添加到加载路径,然后再添加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。在这种情况下,请使用负载,因为它可以更好地表达您要完成的任务。例如:

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

14

我没有像某些答案那样串联路径,而是使用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__。


尝试了所有其他方法后,这似乎绝对是正确的方法,并且最新的答案是+1File.expand_path
— SuckerForMayhem 2014年

我绝对比接受的答案更喜欢此答案。Rails.root.join如果您遇到困难,也可以使用各种答案。
— nzifnab 2014年

14
Dir[File.join(__dir__, "/app/**/*.rb")].each do |file|
  require file
end

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


8

在Rails中,您可以执行以下操作:

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

更新:通过@Jiggneshh Gohel的建议进行了更正,以删除斜杠。


由于Rails.root是一个Pathname实例,因此您可以在任何Ruby环境中执行此操作,而不仅仅是Rails(NB Rails.root.join('lib/ext/*.rb')读起来更好)
— DMKE 2014年

感谢您的推荐;我进行了编辑,以包括您的评论。
— 丹·科恩

对于Rails.root下的子目录使用正斜杠(/),例如Rails.root.join('/lib')不会生成正确的路径。我发现此工具可以正常工作:Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
— Jignesh Gohel 2015年

@Jiggneshh Gohel我按照您的建议删除了斜杠,谢谢。
— 丹·科恩,2015年

3

我参加聚会还晚了几年,但是我有点喜欢这种单线解决方案,我过去曾希望将它包含在应用程序/工作人员/问题中:

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


-2

那又如何require_relative *Dir['relative path']呢?



好的,但是在我的例子中不是。“ *”将arity更改为1。它用作对require_relative的多次调用。
— Aleksander

1
“ *”将Arity更改为1-这是什么意思?require_relative *Dir['*.rb']工作,如果只有一个红宝石脚本。但是,如果找到多个红宝石脚本,您会得到require_relative': wrong number of arguments (4 for 1) (ArgumentError)
— knut
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.