Я знаю в Ruby, что могу использовать respond_to?
проверять, имеет ли объект определенный метод.
Но, учитывая класс, как я могу проверить, имеет ли экземпляр определенный метод?
т.е., что-то как
Foo.new.respond_to?(:bar)
Но я чувствую, что существует, должен быть лучший путь, чем инстанцирование нового экземпляра.
Я не знаю, почему все предлагают использовать instance_methods
и include?
, когда method_defined?
выполняет свою работу.
class Test
def hello; end
end
Test.method_defined? :hello #=> true
ПРИМЕЧАНИЕ
Если вы переходите на Ruby с другого объектно-ориентированного языка ИЛИ думаете, что method_defined
означает ТОЛЬКО методы, которые вы явно определили с помощью:
def my_method
end
, тогда прочтите это:
In Ruby , свойство (атрибут) вашей модели также является методом. Итак, method_defined?
также вернет true для свойств, не только для методов.
Например:
Для экземпляра класса с атрибутом String first_name
:
<instance>.first_name.class #=> String
<instance>.class.method_defined?(:first_name) #=> true
, поскольку first_name
является одновременно атрибутом и методом (и строкой типа String).
Не уверен, что это лучший способ, но вы всегда можете сделать так:
Foo.instance_methods.include? 'bar'
Вы можете использовать method_defined?
следующим образом:
String.method_defined? :upcase # => true
Намного проще, портативнее и эффективнее, чем instance_methods.include?
, который, похоже, предлагают все остальные.
Имейте в виду, что вы не узнаете, реагирует ли класс динамически на некоторые вызовы с method_missing
, например, переопределив respond_to?
, или, начиная с Ruby 1.9.2, определив respond_to_missing?
.
Лучше ответить на вопрос « Для данного класса посмотреть, есть ли у экземпляра метод (Ruby) ». Судя по всему, в Ruby есть встроенная функция, и я ее как-то упустил. В любом случае мой ответ оставлен для справки.
Классы Ruby отвечают на методы instance_methods
и public_instance_methods
. В Ruby 1.8 первый перечисляет все имена методов экземпляра в массиве строк, а второй ограничивает его общедоступными методами. Вы, скорее всего, захотите второго поведения, поскольку response_to?
по умолчанию также ограничивается общедоступными методами.
Foo.public_instance_methods.include?('bar')
В Ruby 1.9, однако эти методы возвращают массивы символов.
Foo.public_instance_methods.include?(:bar)
Если вы планируете делать это часто, вы можете расширить Модуль
, включив в него метод быстрого доступа. (Может показаться странным назначать это 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, это было бы удобным местом для добавления логики для поиска как строк, так и символов.
klass.instance_methods.include :method_name
или "method_name"
, в зависимости от версии Ruby, я думаю.