How do I check if a method is defined on some class directly, not by inheritance or by inclusion/extension? I want something like 'foo?' in the following:
class A
def a; end
end
module B
def b; end
end
class C < A
include B
def c; end
end
C.foo?(:a) #=> false
C.foo?(:b) #=> false
C.foo?(:c) #=> true
The is_a? method will return a true value if an object is a of the type given as a parameter OR if it inherits from the type given as a parameter. So in effect, you can use it to ask "is there going to be a method from a class which I can run on this object".
Use this:
C.instance_methods(false).include?(:a)
C.instance_methods(false).include?(:b)
C.instance_methods(false).include?(:c)
The method instance_methods
return an Array of methods that an instance of this class would have. Passing false
as first parameter returns only methods of this class, not methods of super classes.
So C.instance_methods(false)
returns the list of methods defined by C
.
Then you just have to check if that method is in the returned Array (this is what the include?
calls do).
See docs
For objects you can use Object.respond_to?.
Returns true if obj responds to the given method.
For classes take a look at Module.instance_methods
Returns an array containing the names of the public and protected instance methods in the receiver.
Not exactly an answer to the question, but if you're reading this question, you might be interested in this, which uses .instance_methods(false)
class Object
# This is more or less how Ruby does method lookup internally
def who_responds_to?(method, klass_ancestors = nil)
if klass_ancestors.nil?
return who_responds_to?(method, self.class.ancestors)
end
if klass_ancestors.empty?
return nil
end
if klass_ancestors[0].instance_methods(false).include?(method)
return klass_ancestors[0]
end
klass_ancestors.shift
who_responds_to?(method, klass_ancestors)
end
end
For example
class Person
end
module Drummer
def drum
end
end
module Snowboarder
def jump
end
end
module Engineer
def code
end
end
class Bob < Person
include Drummer
include Snowboarder
include Engineer
def name
end
end
puts "who responds to name"
puts bob.who_responds_to?(:name)
puts "\n"
puts "who responds to code"
puts bob.who_responds_to?(:code)
puts "\n"
puts "who responds to jump"
puts bob.who_responds_to?(:jump)
puts "\n"
puts "who responds to drum"
puts bob.who_responds_to?(:drum)
puts "\n"
puts "who responds to dance"
puts bob.who_responds_to?(:dance)
yields
who responds to name
Bob
who responds to code
Engineer
who responds to jump
Snowboarder
who responds to drum
Drummer
who responds to dance
[this line intentionally blank because return value is nil]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With