0

语境

我通过自动要求目录结构中的所有文件

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

问题

是否有一种“干净”的方式来执行这种类型的自动要求,同时动态避免包含调用自动要求的文件(即api.rb)?

4

2 回答 2

1

请记住,当您require通过某个路径多次识别文件时,每个后续调用都require将返回false,并且不会重新评估该文件。因此,如果您的base.rb(即require其他所有内容)本身就是required,则进一步尝试require它不应导致重新评估。

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

# 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将被评估两次:首先,当它直接执行时;其次,当它是required 时a.rb。请注意,当它需要b.rb.

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

比较require一下。Nowbase.rb只评估一次,因为尝试在requirea.rb之前使用命令行开关b.rb让文件d 进入它。require-r

$ ruby -I lib -r base -e 'puts :ok'
Evaluated base.rb 1 times
a
b
ok
于 2013-01-22T20:51:00.323 回答
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
$
于 2013-03-04T01:09:14.367 回答