我正在尝试覆盖Enumerable模块上的方法,如下所示:
module Enumerable
def collect(&block)
puts 'collect'
super
end
end
(注意这是一个简单的例子)。
理论上,当我调用collect
或map
时,Ruby应该使用我的重写版本,对吧?但事实并非如此。它总是使用内置的Enumerable方法。是因为collect
实际上是enum_collect
并且符合来源吗?
[1,2,3].map(&:to_s) # never prints anything
是的,我知道Monkey-Patching很糟糕,等等,我知道有其他选择,包括子类化等,但我想知道是否有可能覆盖内置的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,但理想情况下我正在寻找适用于所有版本的解决方案。
答案 0 :(得分:5)
我认为你的问题是Array定义了自己的collect
method而不是使用Enumerable:
收集{| item |阻止}→new_ary
map {| item |阻止}→new_ary
收集→an_enumerator
map→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部分与您的问题无关。
答案 1 :(得分:0)
您可以使用相同的方法集在Ruby中迭代许多不同类型的对象。例如,您可以使用包含?迭代Arrays和Hashes以查看它们是否包含特定对象的方法,并类似地使用map方法对它们进行转换。您可能认为每种方法本身都实现了这些方法,但您错了。
在Ruby中,这些类型的方法在Enumerable模块中实现。如果您的类实现了每个方法并包含Enumerable模块,那么您的类将响应涉及集合的大量消息,包括迭代,映射,搜索等。