上下文
我通过
自动要求目录结构中的所有文件# 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
)?
答案 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.rb
。 base.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
只评估一次,因为在require
和a.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
$