动态查找哪个文件包含Ruby中的当前文件

时间:2013-01-22 20:34:25

标签: ruby dependency-management

上下文

我通过

自动要求目录结构中的所有文件
# base.rb
dir = File.dirname(__FILE__)
path = File.join(dir, '**', '*.rb')
Dir[path].each { |file| require File.expand_path(file, __FILE__) }

我正在通过单独文件require中的api.rb语句调用此代码段。

问题

此代码段包含自身(base.rb)以及api.rb

问题

是否有“干净”的方式来执行此类自动要求,同时动态避免包含调用auto-require'er的文件(即api.rb)?

2 个答案:

答案 0 :(得分:1)

请记住,当您require某个路径标识的文件不止一次后,每次对require的后续调用都会返回false,并且不会重新评估该文件。因此,如果base.rb require其他所有内容都是require d,则进一步注意require它不应导致重新评估。

让我们用一个例子来演示它。创建一个包含3个文件的lib目录。

# lib/a.rb

  require 'base'
  puts :a

# lib/b.rb

  require 'base'
  puts :b

# lib/base.rb

  $counter ||= 0
  puts "Evaluated base.rb #{$counter += 1} times"
  dir = File.dirname(__FILE__)
  path = File.join(dir, '**', '*.rb')
  Dir[path].each { |file| require File.expand_path file }

直接执行lib/base.rbbase.rb将被评估两次:首先,它是直接执行的;第二,当require d a.rb时。请注意,从b.rb开始需要 进行评估。

$ ruby -I lib lib/base.rb 
Evaluated base.rb 1 times
Evaluated base.rb 2 times
a
b

require比较。现在base.rb只评估一次,因为在requirea.rb中尝试b.rb之前,使用命令行{{require d 1}}切换。

-r

答案 1 :(得分:0)

Kernel.caller 将当前执行堆栈作为字符串数组返回。你可以避免 在您在该数组中找到的文件名上调用require。多个文件 相同的基本名称会使其绊倒。我没有看到更精确的方法 祖先文件列表。

$ head *.rb
==> A.rb <==
require 'base'
puts :A

==> B.rb <==
require 'base'
puts :B

==> CA.rb <==
require 'base'
puts :CA

==> base.rb <==
dir = File.dirname(__FILE__)
path = File.join(dir, '**', '*.rb')
required = caller.map { |frame| /^(.+):\d+:in `require'$/.match(frame) and File.basename $1 }.compact
Dir[path].each { |file| required.include?(File.basename file) or require File.expand_path file }
$ ruby A.rb
B
CA
A
$ ruby B.rb
A
CA
B
$ ruby CA.rb
A
B
CA
$ ruby base.rb
B
CA
A
$