Issue #12206 has been updated by jeremyevans0 (Jeremy Evans).

Status changed from Open to Closed

This isn't a bug.  `undef_method` and `remove_method` mean two different things in Ruby:

* `remove_method`: Remove the method with this name from the module/class method table
* `undef_method`: Add an entry to the module/class method table, such as Ruby will consider the method not defined if it reaches that entry.

If you prepend `MyMod` to `MyClass`, that means that calling `MyClass.new.foo` looks up methods in the following order:
`MyMod -> MyClass -> Object -> Kernel -> BasicObject`.  So if you `undef_method` in `MyMod`, Ruby raises a `NoMethodError` when it reaches the entry in `MyMod`'s method table, before it reaches the method in `MyClass`'s method table.  `remove_method` works because it removes the entry in the method table in`MyMod`, so lookup proceeds to `MyClass`'s method table.


----------------------------------------
Bug #12206: undef_method on prepended module undefines same-name method on prepending class
https://bugs.ruby-lang.org/issues/12206#change-78898

* Author: EugeneG (Eugene Gilburg)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin12.0]
* Backport: 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN
----------------------------------------
1. Define a class with a method
2. Define a module with a same-name method
3. Prepend the module on the class
4. Undefine the same-name method on the module, not touching the original method on the class
5. Observe the class method to also become undefined
 
~~~
class MyClass
  def foo
    "MyClass#foo"
  end
end

module MyMod
  def foo
    "#{super} prepended by MyMod#foo"
  end
end

MyClass.prepend(MyMod)

MyClass.new.foo
# => "MyClass#foo prepended by MyMod#foo"

MyClass.instance_method(:foo) == MyMod.instance_method(:foo)
# => false

MyMod.send(:undef_method, :foo)

# The bug:

MyClass.new.foo
# => NoMethodError: undefined method `foo' for #<MyClass:0x007ffdf29614a8>
~~~

Expected behavior: `MyClass#foo` would still return "MyClass#foo" since I only undefined `foo` on the module, not on the class.

Real life use case: I'm setting up instrumentation code that can track and measure/benchmark call times of specific methods, but after it's done I want to clean up and restore original code the way it was. For me, it would be even better to support to "unprepend" a module from a class instead of undef_method on the mod, but that's more of a feature request than a bug).



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>