Відповіді:
Я не знаю, чому всі пропонують вам використовувати instance_methods
і include?
коли виконується method_defined?
робота.
class Test
def hello; end
end
Test.method_defined? :hello #=> true
ПРИМІТКА
Якщо ви приїжджаєте до Ruby з іншої мови ООС, або ви думаєте, що це method_defined
означає ТІЛЬКИ методи, які ви чітко визначили:
def my_method
end
потім прочитайте це:
У Ruby властивість (атрибут) для вашої моделі також є методом. Так method_defined?
само повернеться вірно для властивостей, а не лише методів.
Наприклад:
З огляду на екземпляр класу, який має атрибут String first_name
:
<instance>.first_name.class #=> String
<instance>.class.method_defined?(:first_name) #=> true
оскільки first_name
є і атрибутом, і методом (і рядком типу String).
String.instance_methods(false).include? :freeze
, помилковий аргумент може точно вказати, freeze
визначений метод у класі String чи ні. У цьому випадку він повернеться хибним, оскільки freeze
метод успадковується від модуля Kernel String, але String.method_defined? :freeze
завжди поверне true, що не може сильно допомогти з такою метою.
method_defined?
необхідно використовувати в класі (наприклад Array
), але ви намагаєтеся використовувати його в екземплярах (наприклад []
)
Ви можете використовувати method_defined?
наступне:
String.method_defined? :upcase # => true
Набагато простіше, портативніше та ефективніше, ніж instance_methods.include?
всі інші, здається, пропонують.
Майте на увазі, що ви не знатимете, чи відповідає клас динамічно на деякі дзвінки method_missing
, наприклад, шляхом переосмислення respond_to?
або з Ruby 1.9.2 шляхом визначення respond_to_missing?
.
instance.class.method_defined? :upcase
Насправді це не працює як для об'єктів, так і для класів.
Це робить:
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
Відповідь на " Даний клас, подивіться, чи інстанція має метод (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, це було б зручним місцем для додавання логіки і для пошуку і рядків, і символів.
method_defined?
краще :)
Спробуйте Foo.instance_methods.include? :bar
Я думаю, що method_defined?
в Rails щось не так . Це може бути непослідовно чи щось таке, тому якщо ви використовуєте Rails, то краще використовувати щось із attribute_method?(attribute)
.
" тестування на method_defined? на класах ActiveRecord не працює, поки екземпляр " не викликає непослідовність.
Якщо ви перевіряєте, чи може об’єкт реагувати на низку методів, ви можете зробити щось на кшталт:
methods = [:valid?, :chase, :test]
def has_methods?(something, methods)
methods & something.methods == methods
end
the methods & something.methods
will приєднає два масиви на їх загальних / відповідних елементах. something.methods включає всі методи, які ви перевіряєте, вони будуть однаковими методами. Наприклад:
[1,2] & [1,2,3,4,5]
==> [1,2]
так
[1,2] & [1,2,3,4,5] == [1,2]
==> true
У цій ситуації ви хочете використовувати символи, тому що, коли ви викликаєте .methods, він повертає масив символів, і якщо ви використовували ["my", "methods"]
, він повертає помилкові.
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]
Сподіваюся, це допоможе вам!
У моєму випадку, що працює з рубіном 2.5.3, відмінно спрацювали наступні пропозиції:
value = "hello world"
value.methods.include? :upcase
Він поверне булеве значення true чи false.
Хоча respond_to?
повернеться істинно лише для публічних методів, перевірка на "визначення методу" на класі може також стосуватися приватних методів.
На Ruby v2.0 + можна перевірити як державні, так і приватні набори за допомогою
Foo.private_instance_methods.include?(:bar) || Foo.instance_methods.include?(:bar)