2010-07-21 33 views

回答

303

我不知道为什么每个人都建议你应该使用instance_methodsinclude?method_defined?做这项工作。

class Test 
    def hello; end 
end 

Test.method_defined? :hello #=> true 
+1

最简单的答案ftw – user94154 2010-07-22 15:00:51

+8

method_defined?是最好的解决方案,因为instance_methods在Ruby 1.8和1.9之间改变。 1.8返回一个字符串数组,1.9返回一组符号。 method_defined?在1.8和1.9中都有一个符号。 – Jason 2012-05-02 17:03:26

+2

更不用说:instance_methods会在每次调用时创建一个新数组,并且:include?然后将不得不走阵列告诉。相反,:method_defined?将在内部查询方法查找表(一个用C语言进行的哈希查找),并让您知道而不创建任何新对象。 – Asher 2013-07-12 00:40:07

7

对“Given a class, see if instance has method (Ruby)”的回答比较好。显然Ruby有这个内置的,我不知何故错过了它。无论如何,我的答案留作参考。

Ruby类别响应方法instance_methodspublic_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,这将是一个方便的地方添加搜索字符串和符号的逻辑。

+0

'method_defined?'更好:) – horseyguy 2010-07-21 23:31:21

+0

@banister - 哦,我的,我不知何故错过了! xD在@ Marc的回答后面丢了一个+1,并添加了一个链接以确保它不会错过:) – Matchu 2010-07-22 01:05:19

1

klass.instance_methods.include :method_name"method_name",这取决于我认为的Ruby版本。

2

不知道这是最好的方式,但你总是可以做到这一点:

Foo.instance_methods.include? 'bar' 
2

尝试Foo.instance_methods.include? :bar

41

您可以使用method_defined?如下:

String.method_defined? :upcase # => true 

容易得多,比其他人似乎暗示的instance_methods.include?便携和高效。

请记住,你不会知道,如果一个类重新定义respond_to?动态响应某些呼叫与method_missing,例如,或自从红宝石1.9.2定义respond_to_missing?

+1

请注意,如果您手头有实例并且您不知道它是类,则可以执行'instance .class.method_defined? :upcase' – jaydel 2016-10-20 12:55:14

16

实际上,这对于对象和类都不起作用。

这并不:

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 
+3

例如,你也可以使用'instance.class.method_defined?' – Luksurious 2013-10-12 15:16:23

+0

这取决于你的红宝石版本。上述方法适用于所有版本,包括1.8.7。 – 2013-10-16 23:36:35

2

如果你检查是否一个对象可以为一系列的应对方法,你可以这样做:

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"],它'返回假。

1
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] 

希望这可以帮助你!