2012-12-30 76 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中,这些类型的方法可枚举模块中实现。如果你的类实现了每个方法,包括可枚举模块,你的类将涉及收藏,包括迭代,测绘,搜索信息的整体响应主机等