views:

125

answers:

4

Say, I have the following 2 classes:

class A
  def a_method
  end
end

class B < A
end

Is it possible to detect from within (an instance of) class B that method a_method is only defined in the superclass, thus not being overridden in B?

Update: the solution

While I have marked the answer of Chuck as "accepted", later Paolo Perrota made me realize that the solution can apparently be simpler, and it will probably work with earlier versions of Ruby, too.

Detecting if "a_method" is overridden in B:

B.instance_methods(false).include?("a_method")

And for class methods we use singleton_methods similarly:

B.singleton_methods(false).include?("a_class_method")
A: 

you can always to the following and see if its defined there:

a = A.new

a.methods.include?(:method)
ennuikiller
The OP is asking how to detect *from within class B* if it overrides the method or not.Knowing that the class A defines the method doesn't say whether or not the class B overrides it or not.
Carlos Lima
This is fine, but how to additionally detect that the method is *not* (originally) included in the instance methods of B?
Sergei Kozlov
well in b you can still see if A responds to the method, if so and B defines the same method then it obviously overrides A's implementaton
ennuikiller
@Carlos: cheers, you helped me formulate the question better. Have updated the title.
Sergei Kozlov
@ennuikiller: the question remains how to see from B if B defines this method, without parsing the source code... :)
Sergei Kozlov
A: 

Given an object b which is an instance of B, you can test to see whether b's immediate superclass has a_method:

b.class.superclass.instance_methods.include? 'a_method'

Notice that the test is against the method name, not a symbol or a method object.

"thus not being overridden in B" - Just knowing that the method is only defined in A is difficult because you can define the method on an individual instances of A and B... so I think it's going to be difficult to test that a_method is only defined on A, because you'd have to round up all the subclasses and subinstances in the system and test them...

cartoonfox
+6  A: 

If you're using Ruby 1.8.7 or above, it's easy with Method#owner/UnboundMethod#owner.

class Module
  def implements_instance_method(method_name)
    instance_method(method_name).owner == self
    rescue NameError
    false
  end
end
Chuck
Very cool, thanks! Especially happy after seeing the Ruby version that you originally mentioned go down from 1.9 to 1.8.7 (which I'm actually using).
Sergei Kozlov
Yeah, I was a little fuzzy on that. At first I thought it worked with 1.8.7, then saw `Method#owner` wasn't in the 1.8.7 ri docs, so I changed it to 1.9, then I actually checked whether the method existed in 1.8.7 and saw that I had it right the first time. Glad it helps.
Chuck
+2  A: 
class A
  def m1; end
  def m2; end
end

class B < A
  def m1; end
  def m3; end
end

obj = B.new
methods_in_class = obj.class.instance_methods(false)  # => ["m1", "m3"]
methods_in_superclass = obj.class.superclass.instance_methods(false)  # => ["m2", "m1"]
methods_in_superclass - methods_in_class  # => ["m2"]
Paolo Perrotta