2012-01-23 109 views
5

我有一個外部文件中的外部文件:path_to_external_file.rb一些類定義:加載類/模塊

class A 
    some_definitions 
end 

並且我想要加載模塊B使得上文所定義的類A可被稱爲內如B::A。我想:

class B 
    load('path_to_external_file.rb') 
end 

A在主環境中定義,而不是在B

A #=> A 
B.constants # => [] 

我如何可以加載一些類/模塊中的外部文件?

編輯 我應該讀取外部文件作爲字符串,並在Class.new{...}對其進行評估,並includeB這門課嗎?

+0

到底是什麼?爲什麼你不能直接使用A類?你是否從模塊化中獲得了一些好處? 'load'和'require'實際上不會將一個類加載到模塊中,它們只是加載源代碼,因此您的類將按照它們在文件中的定義。不知道你爲什麼想這樣做? – brad

+1

@brad由於這些外部文件要由用戶編寫,並且可以任意命名。如果我在主環境中定義這些類,它們會弄亂命名空間。 – sawa

+0

小心通過'ObjectSpace#each_object'篡改其他名稱空間。 – Reactormonk

回答

4

你不能。至少使用loadrequire,Ruby文件將始終在頂級上下文中進行評估。

您可以解決這個問題有兩種方法:

  • 直接定義class B::A(但你可能想避免)
  • 使用eval(File.read("path_to_external_file.rb"))B類中

編輯:也許這個對你有幫助:https://github.com/dreamcat4/script/blob/master/intro.txt

3

通常,將一個類定義爲「A類」,但然後「神奇地」將它包含在模塊B中是一個壞主意。如果要將類A稱爲B :: A,則應使用以下任一方法對其進行定義:

module B 
    class A 
    # contents 
    end 
end 

或:

class B::A 
    # contents 
end 

否則,任何人誰讀您的代碼將被混淆。在這種情況下,通過使用「技巧」,您不會獲得任何清晰,簡潔或方便的任何內容,因此直接代碼更好。這裏有一個教訓:Ruby的元編程功能非常棒,但不需要無償使用它們。只有當你真正從中獲益時才使用它們。否則,你只是讓你的代碼難以理解。

但是,在閱讀您的評論之後,看起來確實有很好的理由在您的案例中做這樣的事情。我建議下面的解決方案會比你想象的更好:

m = Module.new 
m.module_eval("class C; end") 
m.constants 
=> [:C] 
m.const_get(:C) 
=> #<Module:0xfd0da0>::C 

你看?如果你想要一個「保證唯一」的名字空間,你可以使用匿名模塊。您可以將這些模塊存儲在散列或其他數據結構中,並根據需要將這些模塊拉出。這解決了您提到的問題,即您的應用的用戶將添加他們自己的類,並且您不希望名稱發生衝突。