class C1
unless method_defined? :hello # Certainly, it's not correct. I am asking to find something to do this work.
def_method(:hello) do
puts 'Hi Everyone'
end
end
end
那么,如何判断一个方法是否定义了?如何判断某个方法是否在类中定义?
class C1
unless method_defined? :hello # Certainly, it's not correct. I am asking to find something to do this work.
def_method(:hello) do
puts 'Hi Everyone'
end
end
end
那么,如何判断一个方法是否定义了?如何判断某个方法是否在类中定义?
你发布的代码对于检查方法是否定义工作得很好。 Module#method_defined?
是完全正确的选择。 (还有变种Module#public_method_defined?
,Module#protected_method_defined?
和Module#private_method_defined?
。)问题出在您拨打def_method
时不存在。 (它被称为Module#define_method
)。
这就像一个魅力:
class C1
define_method(:hello) do
puts 'Hi Everyone'
end unless method_defined? :hello
end
不过,既然你已经事先知道名字,不使用任何关闭,也没有必要使用Module#define_method
,你可以只使用def
关键字相反:
class C1
def hello
puts 'Hi Everyone'
end unless method_defined? :hello
end
或者我误解了你的问题,你担心继承?在这种情况下,Module#method_defined?
不是正确的选择,因为它遍历整个继承链。在这种情况下,您将不得不使用Module#instance_methods
或其一个亲戚Module#public_instance_methods
,Module#protected_instance_methods
或Module#private_instance_methods
,它们采用可选参数告诉他们是否包含来自超类/ mixin的方法。 (请注意,文件是错误的:如果你没有传递参数,它将包括所有继承的方法。)
class C1
unless instance_methods(false).include? :hello
def hello
puts 'Hi Everyone'
end
end
end
这里有一个小的测试套件,它表明我的建议的工作:
require 'test/unit'
class TestDefineMethodConditionally < Test::Unit::TestCase
def setup
@c1 = Class.new do
def self.add_hello(who)
define_method(:hello) do
who
end unless method_defined? :hello
end
end
@o = @c1.new
end
def test_that_the_method_doesnt_exist_when_it_hasnt_been_defined_yet
assert [email protected]_defined?(:hello)
assert [email protected]_methods.include?(:hello)
assert [email protected]?(:hello)
assert [email protected]_to?(:hello)
assert_raise(NoMethodError) { @o.hello }
end
def test_that_the_method_does_exist_after_it_has_been_defined
@c1.add_hello 'one'
assert @c1.method_defined?(:hello)
assert @c1.instance_methods.include?(:hello)
assert @o.methods.include?(:hello)
assert_respond_to @o, :hello
assert_nothing_raised { @o.hello }
assert_equal 'one', @o.hello
end
def test_that_the_method_cannot_be_redefined
@c1.add_hello 'one'
assert @c1.method_defined?(:hello)
assert @c1.instance_methods.include?(:hello)
assert @o.methods.include?(:hello)
assert_respond_to @o, :hello
assert_nothing_raised { @o.hello }
assert_equal 'one', @o.hello
@c1.add_hello 'two'
assert @c1.method_defined?(:hello)
assert @c1.instance_methods.include?(:hello)
assert @o.methods.include?(:hello)
assert_respond_to @o, :hello
assert_nothing_raised { @o.hello }
assert_equal 'one', @o.hello, 'it should *still* respond with "one"!'
end
end
Object类有方法 “方法”:docs
class Klass
def kMethod()
end
end
k = Klass.new
k.methods[0..9] #=> ["kMethod", "freeze", "nil?", "is_a?",
# "class", "instance_variable_set",
# "methods", "extend", "__send__", "instance_eval"]
k.methods.length #=> 42
看那Ruby Object class。它有一个methods
函数来获取方法列表和respond_to?
来检查特定的方法。所以你需要这样的代码:
class C1
def add_hello
unless self.respond_to? "hello"
def hello
puts 'Hi Everyone'
end
end
end
end
cone.hello #This would fail
cone.add_hello
cone.hello #This would work
-1,原因有四:1)没有解决OP问题。使用'method_defined?'就好,问题在于他拼写了'define_method'。 2)'respond_to?'不检查特定的方法,它检查对象是否响应特定的消息。 (提示:名称sorta会将它给出,你不觉得吗?)理解方法和消息之间的区别对于理解Ruby甚至是OO是基本的。 3)在你的代码中,你检查类对象'C1'是否响应':hello',并基于你定义'''*'的*实例*的'hello'方法。 ... – 2010-08-04 08:21:12
...再一次:理解*实例*和*类之间的区别*是理解Ruby和基于类的OO的基础。 4)您的测试套件实际上不会测试OP关心的事情,即您无法两次定义该方法。你只测试你可以定义一次方法,但这不是问题。 – 2010-08-04 08:23:32
@jorg,他把'respond_to?'放在一个实例方法('add_hello')中,所以它检查实例(而不是类)。另外,出于好奇,在Ruby中发送消息和调用方法有什么区别? :) – horseyguy 2010-08-04 12:41:05
测试通过1.9.2,但'test_that_the_method_cannot_be_redefined'和'test_that_the_method_does_exist_after_it_has_been_defined'在红宝石1.8.7下失败。 – mrm 2011-08-22 18:27:40