2009-07-11 61 views
2

在紅寶石中是否有require的版本,要麼加載整個文件,要麼根本沒有?Ruby中的全部或無要求?

的問題是,需要從頂部開始加載,如果它面臨着你最終未完成的定義問題,例如,下面仍然會加載一個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 

我最終會想把它加載,然後找到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會解決它。

任何想法?

回答

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時,它首先會看到a的要求並意識到它已被加載,那麼它將需要c,因爲它意識到它尚未加載它。當再次需要c時,它將從外部循環中跳過它。

注意:請注意您的$ LOAD_PATH以及傳遞給require的路徑。當路徑相同時,Ruby只能識別重複的需求。最好使用相對路徑(相對於$ LOAD_PATH中的路徑)而不是絕對路徑;否則,文件可能會加載兩次。

+0

謝謝,我知道我可以在每個文件中使用`require`,但我希望它是_automatic_。我提出了一個複雜的解決方案(運行第二個ruby實例作爲沙箱來測試需求),但看起來這是最好的做法,所以我會去做:) – 2009-07-12 08:14:45