Учитывая класс, посмотрите, имеет ли экземпляр метод (Ruby)

Я знаю в Ruby, что я могу использовать respond_to?, чтобы проверить, имеет ли объект определенный метод.

Но, учитывая класс, как я могу проверить, имеет ли экземпляр определенный метод?

i.e, что-то вроде

Foo.new.respond_to?(:bar)

Но я чувствую, что должен быть лучший способ, чем создавать экземпляр нового экземпляра.

Ответ 1

Я не знаю, почему все предлагают вам использовать instance_methods и include? когда method_defined? делает работу

class Test
  def hello; end
end

Test.method_defined? :hello #=> true

НОТА

В случае, если вы method_defined на Ruby с другого языка OO, ИЛИ вы думаете, что method_defined означает ТОЛЬКО методы, которые вы определили явно:

def my_method
end

тогда прочитайте это:

В Ruby свойство (атрибут) вашей модели также является в основном методом. Итак, method_defined? также вернет true для свойств, а не только для методов.

Например:

Дан экземпляр класса с атрибутом String first_name:

<instance>.first_name.class #=> String

<instance>.class.method_defined?(:first_name) #=> true

поскольку first_name является одновременно атрибутом и методом (и строкой типа String).

Ответ 2

Вы можете использовать method_defined? следующим образом:

String.method_defined? :upcase # => true

Намного проще, портативнее и эффективнее, чем instance_methods.include?, кажется, предлагают все остальные.

Имейте в виду, что вы не будете знать, динамически реагирует ли класс на некоторые вызовы с помощью method_missing, например, путем переопределения respond_to? или с Ruby 1.9.2 путем определения respond_to_missing?.

Ответ 3

На самом деле это не работает для объектов и классов.

Это делает:

class TestClass
  def methodName
  end
end

Таким образом, с данным ответом, это работает:

TestClass.method_defined? :methodName # => TRUE

Но это НЕ работает:

t = TestClass.new
t.method_defined? : methodName  # => ERROR!

Поэтому я использую это для обоих классов и объектов:

Классы:

TestClass.methods.include? 'methodName'  # => TRUE

Объекты:

t = TestClass.new
t.methods.include? 'methodName'  # => TRUE

Ответ 4

Ответ на Учитывая класс, посмотрите, лучше ли экземпляр метода (Ruby). Очевидно, Ruby имеет этот встроенный модуль, и я как-то его пропустил. Мой ответ оставлен для справки, независимо.

классы Ruby отвечают на методы instance_methods и public_instance_methods. В Ruby 1.8 первое перечисляет все имена методов экземпляра в массиве строк, а второе ограничивает его общедоступными методами. Второе поведение - это то, что вы, скорее всего, захотите, так как respond_to? также ограничивается общедоступными методами по умолчанию.

Foo.public_instance_methods.include?('bar')

В Ruby 1.9 эти методы возвращают массивы символов.

Foo.public_instance_methods.include?(:bar)

Если вы планируете делать это часто, вы можете расширить Module, чтобы включить метод быстрого доступа. (Может показаться странным присвоить это Module вместо Class, но поскольку там, где существуют методы instance_methods, лучше всего придерживаться этого шаблона.)

class Module
  def instance_respond_to?(method_name)
    public_instance_methods.include?(method_name)
  end
end

Если вы хотите поддерживать как Ruby 1.8, так и Ruby 1.9, это было бы удобным местом для добавления логики для поиска как строк, так и символов.

Ответ 5

Не уверен, что это лучший способ, но вы всегда можете это сделать:

Foo.instance_methods.include? 'bar'

Ответ 6

Попробуйте Foo.instance_methods.include? :bar

Ответ 7

Если вы проверяете, может ли объект реагировать на ряд методов, вы можете сделать что-то вроде:

methods = [:valid?, :chase, :test]

def has_methods?(something, methods)
  methods & something.methods == methods
end

methods & something.methods присоединяется к двум массивам на их общих/согласованных элементах. something.methods включает в себя все методы, которые вы проверяете, это будет равным методам. Например:

[1,2] & [1,2,3,4,5]
==> [1,2]

так

[1,2] & [1,2,3,4,5] == [1,2]
==> true

В этой ситуации вы хотите использовать символы, потому что когда вы вызываете методы., он возвращает массив символов, и если вы использовали ["my", "methods"], он возвращал бы false.

Ответ 8

Я думаю, что что-то не так с method_defined? в Rails. Это может быть непоследовательно или что-то в этом роде, поэтому, если вы используете Rails, лучше использовать что-то из attribute_method?(attribute).

"тестирование для method_defined? на классах ActiveRecord не работает до тех пор, пока экземпляр не станет вопросом о несогласованности.

Ответ 9

klass.instance_methods.include :method_name или "method_name", в зависимости от версии Ruby, я думаю.

Ответ 10

class Foo
 def self.fclass_method
 end
 def finstance_method
 end
end

foo_obj = Foo.new
foo_obj.class.methods(false)
=> [:fclass_method] 

foo_obj.class.instance_methods(false)
=> [:fclass_method] 

Надеюсь, это поможет вам!

Ответ 11

В моем случае, работающем с ruby 2.5.3, следующие предложения сработали отлично:

value = "hello world"

value.methods.include? :upcase

Он вернет логическое значение true или false.