I'm trying to overwrite a method on the Enumerable module like this:
module Enumerable
def collect(&block)
puts 'collect'
super
end
end
(Note this is a trivial example).
Theoretically, when I call collect
or map
, Ruby should use my overridden version, right? But it's not. It always uses the built-in Enumerable method. Is it because collect
is actually enum_collect
and complied with the source?
[1,2,3].map(&:to_s) # never prints anything
Yes, I'm aware that Monkey-Patching is bad, etc, etc, and I'm aware there are alternatives including subclassing, etc, but I want to know if it's possible to overwrite a built-in C function with Ruby.
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)
and pretty much every combination thereof.
PS. This is Ruby 1.9.3, but ideally I'm looking for a solution that would work on all versions.
I think your problem is that Array defines its own collect
method rather than using Enumerable's:
collect {|item| block } → new_ary
map {|item| block } → new_ary
collect → an_enumerator
map → an_enumeratorInvokes block once for each element of
self
. Creates a new array containing the values returned by the block. See alsoEnumerable#collect
.
So you can monkey patch Enumerable#collect
all you want but Array
won't care because it doesn't use Enumerable#collect
. You'll have better luck if you monkey patch Array#collect
:
class Array
def collect
#...
end
end
You'll want to patch Array#map
as well or just patch map
and let the alias take care of collect
.
Note that Array#map
is implemented in C so the C part had nothing to do with your problem.