Подтвердить что ты не робот

Проверка, если метод определен в классе

Как проверить, определен ли метод для определенного класса, а не по наследованию или включению/расширению? Я хочу что-то вроде "foo?" в следующем:

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
4b9b3361

Ответ 1

Используйте это:

C.instance_methods(false).include?(:a)
C.instance_methods(false).include?(:b)
C.instance_methods(false).include?(:c)

Метод instance_methods возвращает массив методов, который будет иметь экземпляр этого класса. Передача false в качестве первого параметра возвращает только методы этого класса, а не методы суперклассов.

Итак, C.instance_methods(false) возвращает список методов, определенных C.

Затем вам просто нужно проверить, находится ли этот метод в возвращаемом массиве (это то, что делают вызовы include?).

См. документы

Ответ 2

Для объектов вы можете использовать Object.respond_to?.

Возвращает true, если obj отвечает данному методу.

Для классов взгляните на Module.instance_methods

Возвращает массив, содержащий имена общедоступных и защищенных методов экземпляра в приемнике.

Ответ 3

Не совсем ответ на вопрос, но если вы читаете этот вопрос, вам может быть интересно это, в котором используется .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

Например

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)

дает

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]