我知道在 Ruby 中我可以respond_to?
用来检查一个对象是否有某种方法。
但是,给定类,我如何检查实例是否具有某种方法?
即,类似
Foo.new.respond_to?(:bar)
但我觉得肯定有比实例化新实例更好的方法。
我知道在 Ruby 中我可以respond_to?
用来检查一个对象是否有某种方法。
但是,给定类,我如何检查实例是否具有某种方法?
即,类似
Foo.new.respond_to?(:bar)
但我觉得肯定有比实例化新实例更好的方法。
我不知道为什么每个人都建议您应该使用instance_methods
以及include?
何时method_defined?
完成这项工作。
class Test
def hello; end
end
Test.method_defined? :hello #=> true
笔记
如果您从另一种 OO 语言开始使用 Ruby,或者您认为这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
既是属性又是方法(以及字符串类型的字符串)。
您可以method_defined?
按如下方式使用:
String.method_defined? :upcase # => true
比instance_methods.include?
其他人似乎暗示的要容易、便携和高效。
请记住,您不会知道一个类是否动态响应某些调用method_missing
,例如通过重新定义respond_to?
,或者从 Ruby 1.9.2 开始通过定义respond_to_missing?
.
实际上,这对对象和类都不起作用。
这样做:
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 有这个内置的,我不知何故错过了它。无论如何,我的答案仅供参考。
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,那么这将是一个方便的地方,可以添加搜索字符串和符号的逻辑。
尝试Foo.instance_methods.include? :bar
不确定这是否是最好的方法,但你总是可以这样做:
Foo.instance_methods.include? 'bar'
如果您正在检查一个对象是否可以响应一系列方法,您可以执行以下操作:
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
在这种情况下,你会想要使用符号,因为当你调用 .methods 时,它会返回一个符号数组,如果你使用["my", "methods"]
了,它会返回 false。
我认为method_defined?
Rails 有问题。它可能不一致或什么,所以如果你使用 Rails,最好使用来自attribute_method?(attribute)
.
“在实例化之前在 ActiveRecord 类上测试 method_defined? ”是关于不一致的问题。
klass.instance_methods.include :method_name
或者"method_name"
,取决于我认为的 Ruby 版本。
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]
希望这对你有帮助!
虽然respond_to?
只会对公共方法返回 true,但检查类上的“方法定义”也可能与私有方法有关。
在 Ruby v2.0+ 上,可以通过以下方式检查公共集和私有集
Foo.private_instance_methods.include?(:bar) || Foo.instance_methods.include?(:bar)
在我使用 ruby 2.5.3 的情况下,以下句子效果很好:
value = "hello world"
value.methods.include? :upcase
它将返回一个布尔值 true 或 false。