2012-12-30 100 views
2

我想覆蓋的方法這樣可枚舉模塊:紅寶石覆蓋可枚舉法

​​

(注意,這是一個簡單的例子)。

理論上,當我撥打collectmap時,Ruby應該使用我的重寫版本,對不對?但事實並非如此。它始終使用內置的Enumerable方法。是否因爲collect實際上是enum_collect並且符合來源?

[1,2,3].map(&:to_s) # never prints anything 

是的,我知道,猴子,修補是壞的,等等,等等,我知道有替代品,包括子類,等等,但我想知道是否有可能覆蓋一個內置在Ruby中使用C函數。

Enumerable.class_eval do 
    def collect(&block) 
    puts 'collect was class_eval' 
    super 
    end 
end 

 

eigen = class << Enumerable; self; end 
eigen.class_eval do 
    def collect(&block) 
    puts 'collect was eigen' 
    super 
    end 
end 

 

module Enumerable 
    def collect(&block) 
    puts 'collect was opened up' 
    super 
    end 
end 

 

Array.send(:include, Enumerable) 

和幾乎其每一組合。

PS。這是Ruby 1.9.3,但理想情況下,我正在尋找一種適用於所有版本的解決方案。

+1

第一個問題是,爲什麼呢?爲什麼不寫一個類,混合使用Enumerable('include Enumerable'),然後定義'each'來做你想做的事?這樣*所有*可枚舉的方法的行爲方式,你想要的類,你可以繼承,如果需要的話。 – mrlee

+0

「我知道有其他選擇,包括子類化等,但我想知道是否有可能用Ruby覆蓋內置的C函數。」我想改變地圖在所有Enumerable對象上的工作方式。我沒有說任何關於'each'的... – sethvargo

+0

運行這個,看看它是*全部*關於'each':https://gist.github.com/4410424。它沒有具體回答你的問題,但它可以讓你持續改變Enumerable行爲。 – mrlee

回答

5

我覺得你的問題是,數組定義了自己的collect method而不是使用可枚舉的:

收集{|項目|塊}→new_ary
map {| item |塊}→new_ary
收集→an_enumerator
地圖→an_enumerator

調用一次的self每個元素。創建一個包含塊返回值的新數組。另見Enumerable#collect

這樣你就可以猴子補丁Enumerable#collect所有你想要的,但Array不會在意,因爲它不使用Enumerable#collect。你有更好的運氣,如果你的猴子補丁Array#collect

class Array 
    def collect 
    #... 
    end 
end 

你想修補Array#map以及或者只是修補map,讓別名採取collect照顧。

請注意,Array#map在C中實現,因此C部分與您的問題無關。

+0

哇。我覺得我好笨。這是令人難以置信的誤導,認爲'Array'包含'Enumerable',然後爲那些實現自己的方法...我正在閱讀以編寫自定義的C擴展! – sethvargo

+1

我想'Array'由於性能的原因自己做了很多'Enumerable'的東西,數組確實有一個特殊的結構,迭代可以充分利用畢竟。 –

0

可以使用同一套方法迭代許多不同類型的對象在Ruby中。例如,你可以使用包含?方法遍歷數組和哈希以查看它們是否包含特定的對象,並同樣使用映射方法來轉換它們。你可能會認爲每種方法都自己實現這些方法,但是你會錯的。

在Ruby中,這些類型的方法可枚舉模塊中實現。如果你的類實現了每個方法,包括可枚舉模塊,你的類將涉及收藏,包括迭代,測繪,搜索信息的整體響應主機等