Ruby中是全是还是没有要求?

时间:2009-07-11 11:22:56

标签: ruby require

ruby​​中是否有require版本可以加载整个文件,还是什么都没有?

问题是需要从顶部开始加载,如果遇到问题,最终会出现未完成的定义,例如,即使未定义class A,以下内容仍会加载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可以解决它。

有什么想法吗?

1 个答案:

答案 0 :(得分: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

之后,外部加载顺序不再重要,“all-or-nothing”也不需要接近。加载b后,它会首先看到a的要求并意识到它已经加载,然后它将需要c,因为它意识到它尚未加载它。当再次需要c时,它将从外循环中跳过它。

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