Problems extending Enumerable
I wrote how to add a simple method to Enumerable
in a previous post
module Enumerable
def measure(&block)
Benchmark.measure do
ActiveRecord::Base.logger.silence do
self.tqdm.each(&block)
end
end
end
end
I wanted to follow the points in this article 3 Ways to Monkey-patch Without Making a Mess, but there seems to be some cases in which this technique can’t be applied, at least the part regarding putting your method in a module.
In order to make other developers aware of this monkey patches, we start by requiring it inside an initializer in config/initializers/monkey_patches.rb
require 'core_extensions/enumerable/progress_benchmark'
then I add a file at lib/core_extensions/enumerable/progress_benchmark
following rails conventions
module CoreExtensions
module Enumerable
module ProgressBenchmark
def measure(&block)
Benchmark.measure do
ActiveRecord::Base.logger.silence do
self.tqdm.each(&block)
end
end
end
end
end
end
Enumerable.include CoreExtensions::Enumerable::ProgressBenchmark
if we try it now in the console:
[].measure
#NoMethodError: undefined method `method' for []:Array
it would exist if we include Enumerable
now:
class Foo
include Enumerable
end
Foo.new.measure
#NoMethodError: super: no superclass method `each' (it's ok, it has been included )
Seems that including methods this way doesn’t work when you refer to classes that have already included that module. These posts speak about a limitation on the current ruby implementation:
This however works well just reopening the module, as originally.
Active Support reopens as well
A workaround would be do something like this, to iterate through the object space, find all the classes that had previously included Enumerable
and include it again:
ObjectSpace.each_object(Class) do |klass|
if klass.include?(Enumerable )
klass.include CoreExtensions::Enumerable::ProgressBenchmark)
end
end
Not sure whether this is a good idea yet.