2011-11-25 74 views
2

我想提出一個方法,一個Ruby模塊,使得它可以從一個類的方法實例方法被調用,使用簡單的語法:我該如何聲明一個mixin方法,使它可以在實例方法和類方法中使用?

module MyMod 
    def fmt *args 
    args.map { | a | "You said #{a}" } 
    end 
end 

class MyClass 
    include MyMod 
    def inst 
    puts fmt 1,2,3 
    end 
    def self.cls 
    puts fmt 4,5,6 
    end 
end 

上述不起作用,因爲該類方法(cls)無法看到實例方法fmt。如果我將定義更改爲self.fmt,那麼實例方法必須將其調用爲MyMod.fmt

我希望能夠從兩種類型的方法中調用fmt (some stuff)。有沒有一種「ruby-ish」的方式來做到這一點?我可以定義模塊爲

module MyMod 
    def self.fmt *args 
    args.map { | a | "You said #{a}" } 
    end 
    def fmt *args 
    MyMod.fmt args 
    end 
end 

但這不是很乾,是嗎?有一種更簡單的方法嗎?

回答

5

您可以使用優勢Module#included方法做這樣的:

module MyMod 
    # here base is a class the module is included into 
    def self.included(base) 
    # extend includes all methods of the module as class methods 
    # into the target class 
    base.extend self 
    end 

    def fmt(*args) 
    args.map { |a| "You said #{a}" } 
    end 
end 

class MyClass 
    # regular include provides us with instance methods 
    # and defined above MyMod#included hook - with class methods 
    include MyMod 

    def inst 
    puts fmt(1, 2, 3) 
    end 

    def self.cls 
    puts fmt(4, 5, 6) 
    end 
end 

puts MyClass.cls 
puts MyClass.new.inst 

而這裏的輸出:

You said 4 
You said 5 
You said 6 

You said 1 
You said 2 
You said 3 

對於更詳細的解釋看看this article

+0

當構建一些可以作爲其他開發人員應該包含在他們的類中的DSL時,這種回調是很好的。否則,這太神奇了,無法證明是合理的,因爲使用'include'會導致添加類方法並不明確。因此,如果這是在內部代碼中,手動使用'extend'本身幾乎總是有益的,而不是經歷記錄該特殊行爲的麻煩。 –

+0

好點,但是如果你想在多個地方使用這個模塊,我不認爲在需要的時候同時調用'include'和'extend'是個很好的解決方案。 –

+0

@ KL-7,爲什麼不呢?該模塊正在爲你做這個......你不必這樣做。無論如何,這是唯一的方法。 – d11wtq

1

兩個includeextendMyMod模塊中MyClass,使得fmt方法被添加既作爲一個實例,並一類方法來MyClass

Object#extend所做的是將模塊的方法添加到單個實例。在這種情況下,該實例就是類本身,這就是爲什麼這些方法可用作類方法。

相關問題