I would like to print the class and method any time a method gets redefined in a Rails app, even if it happens in an included gem. I understand there is a hook called method_added
that gets called back on redefining a method, but I do not know how to use it to catch anything that gets redefined.
How do I use method_added
?
I added this to boot.rb:
class Module
def method_added(name)
puts "adding #{self.name.underscore.capitalize} #{name}\n"
end
end
But that seems to be catching every single method in every single class?
You can use the Module#method_added
hook to keep a record of all methods that are being defined, and check whether you have already seen the same method before:
require 'set'
module LoggingMethodAdded
def method_added(meth)
@methods ||= Set.new
puts "Monkey patching #{meth} in #{self}!" if @methods.include?(meth)
@methods << meth
super
end
end
class Module
prepend LoggingMethodAdded
end
class Foo; def foo; end end
class Foo; def foo; end end
# Monkey patching foo in Foo!
module Bar; def foo; end end
module Bar; def foo; end end
# Monkey patching foo in Bar!
This, however, will only work for methods that are added after you have loaded your hook method. The obvious alternative would be to check the already defined methods instead of recording them yourself:
def method_added(meth)
puts "Monkey patching #{meth} in #{self}!" if (instance_methods(false) | private_instance_methods(false)).include?(meth)
super
end
But this doesn't work: it is not exactly specified when the method_added
hook gets executed; it might get executed after the method has been defined, which means the check will always be true. (At least that's what happened in my tests.)