在Ruby中,是否可以递归地要求目录中的所有文件?

20

我正在开发一个API,需要加载当前目录及其所有子目录中的所有.rb文件。目前,每添加一个文件都要输入一个新的require语句,但我希望只需将文件放在其中一个子目录中,就可以自动添加。

是否有标准命令可以实现这一点?


1
只是一点小提示:要求一组可能未知的文件是危险的,也可能导致错误。假设我放了一个名为 die.rb 的文件,并在其中加入了一个退出语句(抱歉,没有实际的代码,我从未使用过 Ruby),一旦加载它,程序就会结束。或者,如果用户删除了一个文件呢?该文件提供的函数将无法加载。如果你只是想忽略安全问题,并包含这些文件并检查确保它们已被加载(通过调用某种检查函数),可能会起作用,但是再次强调,我没有 Ruby 经验。 - HalfBrian
为什么要在项目中放置 die.rb?如果该项目已经很老并且已经收集了垃圾,我同意这是危险的。然而,对于一个相对较新的项目来说,这是一个明智的举动,可以防止某人意外地将 die.rb 添加到代码库中(它会在加载时失败/错误更早地变得明显)。 - Adamantish
6个回答

45
在这种情况下,它正在加载 lib 目录下的所有文件:
Dir["#{File.dirname(__FILE__)}/lib/**/*.rb"].each { |f| load(f) }

1
为什么你使用 load 而不是 require - johannes
你可以使用两者,但是通常需要将require传递一个库名称,而不是文件名及其扩展名。 - Filipe Miguel Fonseca
2
但是 require 不介意你传入扩展名,所以在我看来这是更可取的。 - johannes
15
如果你使用 require,这个文件会被视为源文件并作为库加载。使用 load 则会将文件作为脚本运行,并防止加载文件中的任何局部变量被导入到当前环境中。Ruby也允许你使用 load 重新导入一个文件,但不能使用 require。这里可以使用任一语法,只要确保它执行的是你所期望的操作。 - bta
1
“库”毕竟只是文件。当你使用require 'bundler'时,Ruby会在bundler gem的lib目录中找到bundler.rb文件并运行其中的代码。 - Nathan

6
require "find"

Find.find(folder) do |file|
  next if File.extname(file) != ".rb"
  puts "loading #{file}"
  load(file)
end

这将递归加载每个.rb文件。

4

就像Miguel Fonseca所说的那样,在Ruby >= 2中,你可以这样做:

    Dir[File.expand_path "lib/**/*.rb"].each{|f| require_relative(f)}

2

我经常使用gem require_all,并通过以下方式在您的requires中完成工作:

require 'require_all'
require_all './lib/exceptions/'

0
def rLoad(dir)
    Dir.entries(dir).each {|f|
        next if f=='.' or f=='..'
        if File.directory?(f)
            rInclude(f)
        else
            load(f) if File.fnmatch('*.rb', f)
        end
    }
end

这应该递归地加载指定目录中的所有.rb文件。例如,rLoad Dir.pwd将在当前工作目录上运行。

但是要小心执行此操作。这会进行深度优先搜索,如果您的Ruby脚本中存在任何冲突的定义,则可能以某种非明显的方式解决它们(我相信是按文件夹/文件名称的字母顺序)。


你的load调用中为什么不直接匹配f - Geo
如果你正在引用语句 File.fnmatch('*.rb', f),该语句将在文件名 f 匹配模式 *.rb 时返回 true。这确保我们只加载 Ruby 脚本,而不是文件夹中可能存在的其他文件。请注意,如果您还有使用 .rbw 扩展名的脚本,则可能需要添加另一个条件。 - bta
是的。但是你可以使用load(f) if f =~/\.rb/。我指的是为什么要使用fnmatch而不是内置的正则表达式支持。 - Geo
啊,我现在明白你的意思了。当我写上面的代码时,我正在处理另一个使用fnmatch方法的东西,所以那一行基本上是复制/粘贴的。我想~/\.rb$/正则表达式也可以工作(添加了$以防止匹配像“script.rb.bak”这样的文件)。 - bta

0
你应该看一下这个gem。它非常小,所以你可以重复使用代码而不是安装整个 gem。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接