2

requireファイル全体をロードするか、まったくロードしないバージョンの in 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

ローダーは、現在のファイルのリストを取得し、それらを 1 つずつ要求しようとします。いずれかのファイルが失敗した場合、そのファイルはリストに残り、後で再試行されます。コードは次のようなものです: (簡単にするために多くの詳細を削除しました)

# 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ロードされると、最初にrequireを確認し、すでにaロードされていることを認識します。次に、cまだロードされていないことを認識するため、requireを実行します。cが再度必要になると、外側のループからスキップされます。

注:$LOAD_PATHとに渡されるパスに注意してくださいrequire。Rubyは、パスが同じ場合にのみ重複要件を認識します。絶対パスではなく、相対パス($ LOAD_PATH内のパスを基準とする)を使用することをお勧めします。そうしないと、ファイルが2回ロードされる可能性があります。

于 2009-07-11T14:30:08.070 に答える