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