【问题标题】:Best way to require all files from a directory in ruby?要求ruby目录中所有文件的最佳方法?
【发布时间】:2010-10-18 14:48:00
【问题描述】:

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

【问题讨论】:

    标签: ruby file directory require


    【解决方案1】:

    怎么样:

    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,其中“聪明”的自动加载展示了他在旧版本中描述的行为(并且可能仍然存在)。
    【解决方案2】:

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

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

    编辑:基于下面的 cmets,更新版本:

    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 要求目录中的所有文件?
    【解决方案3】:

    试试 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 请注意,require_all 的循环依赖解析解决了源代码中的一个问题:您拥有不需要依赖关系的 Ruby 源文件。这关闭了手术刀装载的大门,让您全有或全无装载。这在小型图书馆中不是问题,但您应该有意识地做出决定。
    • 用可以简单地用一行代码替换的 gem 来膨胀你的应用程序是没有意义的。从长远来看,这会增加应用的加载时间并引发更多错误。
    【解决方案4】:
    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,其中“聪明”的自动加载表现出旧版本中描述的行为(并且可能仍然存在)。
    【解决方案5】:
    Dir.glob(File.join('path', '**', '*.rb'), &method(:require))
    

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

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

    解释:

    Dir.glob 将块作为参数。

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

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

    【讨论】:

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

    最好的方法是将目录添加到加载路径,然后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 意识到这些是同一个文件的路径。
    【解决方案7】:
    Dir[File.join(__dir__, "/app/**/*.rb")].each do |file|
      require file
    end
    

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

    【讨论】:

      【解决方案8】:

      我没有像某些答案那样连接路径,而是使用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__ 的文件名。

      【讨论】:

      • 这似乎绝对是要走的路,而且是最新的答案,在尝试了所有其他方法之后,+1 File.expand_path
      • 比起公认的答案,我绝对更喜欢这个答案。如果您在 Rails 中,各种Rails.root.join 答案也可以使用。
      【解决方案9】:

      在 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 我按照你的建议删除了斜杠,谢谢。
      【解决方案10】:

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

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

      【讨论】:

        【解决方案11】:

        那么: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)
        猜你喜欢
        • 2011-01-30
        • 2019-02-08
        • 2010-10-21
        • 2011-01-30
        • 1970-01-01
        • 2012-12-15
        • 1970-01-01
        相关资源
        最近更新 更多