hector
hector

Reputation: 967

Remove a method only from an instance

Is it possible to remove a method from a single instance?

class Foo
  def a_method
    "a method was invoked"
  end
end

f1 = Foo.new
puts f1.a_method # => a method was invoked

I can remove a_method from the class an from the already created object with this:

class Foo
  remove_method(:a_method)
end

If I invoke a_method from the same object:

puts f1.a_method # => undefined method

If I create another object:

f2 = Foo.new
puts f2.a_method # => undefined method

How can I only remove a method from an specific single object?

Upvotes: 15

Views: 3674

Answers (2)

Alexander
Alexander

Reputation: 63167

You can call undef_method on the singleton class of the object you care about:

f1.singleton_class.undef_method(:a_method)

Explanation

Don't confuse remove_method and undef_method. They look similar, but have quite different behaviour. The docs of undef_method explain it as:

Prevents the current class from responding to calls to the named method. Contrast this with remove_method, which deletes the method from the particular class; Ruby will still search superclasses and mixed-in modules for a possible receiver.

Module#remove_method

...will delete a method from a particular Module/Class' method table.

That doesn't mean that the message (e.g. a_method) can't still be sent to objects of that class.

It'll behave as if you didn't define a method implementation in that Module/Class, so regular inheritance behaviour will still occur: method resolution will continuing its search up the ancestor chain.

Here's an example:

class Parent
  def m = "The parent implementation"
end

class Child < Parent
  def m = "The child override"

  remove_method :m # Behaves as if `m` was commented out above
end

p Child.new.m # => "The parent implementation"

Module#undef_method

... will define a special method in the Module/Class' method table with a special type (VM_METHOD_TYPE_UNDEF), which behaves as if it had an implementation that just raises.

Attempting to call this method will find this stub, and terminate the search (not searching up the ancestor chain). Its implementation just raises.

class Parent
  def m = "The parent implementation"
end

class Child < Parent
  def m = "The child override"

  undef_method :m # Behaves as if `m` was defined as `= raise NoMethodError`
end

p Child.new.m # => NoMethodError

Upvotes: 2

Agis
Agis

Reputation: 33626

Yes, it is possible:

f1.instance_eval('undef :a_method')

Upvotes: 23

Related Questions