2

是否有一个版本的requirein ruby​​ 可以加载整个文件,或者什么都不加载?

class A问题是 require 从顶部开始加载,如果遇到问题,您最终会得到未完成的定义,例如,即使module C未定义,以下内容仍会加载:

class B
  include C
end

在我的特殊情况下,我有大量相互依赖的文件,以及一个加载这些文件的加载器。为了举例说明,我将简单地将文件集设置为 4 个文件(a.rb、b.rb、c.rb 和 w.rb)。以下是这些文件的列表:

# In file a.rb
class A
  @foo = []
  @foo.push("in A")

  def self.inherited(subclass)
    foo = @foo.dup
    subclass.instance_eval do
      @foo = foo
    end
  end

  def self.get_foo
    @foo
  end
end

# In file b.rb
class B < A
  include C # if C is not already defined, the following line will not get executed although B will be defined.
  @foo.push("in B")
end

# In file c.rb
module C
end

# In file w.rb
class W < B
  @foo.push("in W")
end

加载器通过获取当前文件的列表来工作,并尝试一个一个地要求它们。如果任何文件失败,它会保留在列表中并稍后重试。代码是这样的:(为简单起见,删除了很多细节)

# In file loader.rb
files = Dir["*.rb"].reject { |f| f =~ /loader/ }
files.sort! # just for the purpose of the example, to make them load in an order that causes the problem
files.reject! { |f| require(f) rescue nil } while files.size > 0

我最终希望它加载A,然后发现B不能单独加载(所以跳过它),然后加载C,然后发现W还不能加载(所以跳过它),然后回到B然后W .

在这种情况下,输出p W.get_foo将是["in A", "in B", "in W"],这就是我想要的。

实际发生的是它加载 A,然后部分加载 B,然后是 C,然后当涉及到 W 时,它相信它可以加载它(因为 B 已经定义)。这会在不正确的时间触发self.inherited代码,并复制尚未就绪的 值@foo,从而将 的输出p W.get_foo错误地设为["in A", "in W"]

有一个全有或全无require将解决它。

有任何想法吗?

4

1 回答 1

5

如果一个文件依赖于另一个文件,则该文件应该需要依赖项本身。例如,b.rb应该如下所示:

require 'a'
require 'c'

class B < A
  include C # if C is not already defined, the following line will not get executed although B will be defined.
  @foo.push("in B")
end

w.rb应该是这样的:

require 'b'

class W < B
  @foo.push("in W")
end

之后,外部加载顺序不再重要,“全有或全无”要求方法也不再重要。加载时b,它会首先看到 requirea并意识到它已经被加载,然后它会c因为它意识到它还没有加载它而需要它。当再次需要 c 时,它将从外循环中跳过它。

注意:请注意您的 $LOAD_PATH 和传递给require. Ruby 仅在路径相同时识别重复需求。最好使用相对路径(相对于 $LOAD_PATH 中的路径)而不是绝对路径;否则,一个文件可能会被加载两次。

于 2009-07-11T14:30:08.070 回答