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