【发布时间】:2012-08-07 07:42:59
【问题描述】:
我想重新定义一个方法,但要避免与之相关的警告。我应该使用 undef_method 还是 remove_method 这样做?
(是的,重新定义方法有点麻烦。我这样做是因为我有一些我想在运行单元测试时使用的记忆,而不是在运行程序本身时使用。)
【问题讨论】:
标签: ruby reflection methods metaprogramming
我想重新定义一个方法,但要避免与之相关的警告。我应该使用 undef_method 还是 remove_method 这样做?
(是的,重新定义方法有点麻烦。我这样做是因为我有一些我想在运行单元测试时使用的记忆,而不是在运行程序本身时使用。)
【问题讨论】:
标签: ruby reflection methods metaprogramming
来自fine manual:
undef_method(symbol) → self
防止当前类响应对命名方法的调用。将此与
remove_method进行对比,后者从特定类中删除方法; Ruby 仍会在超类和混合模块中搜索可能的接收器。
所以remove_method 是这样的:
class CC < C
remove_method :m
end
本质上与此相反:
class CC < C
def m
end
end
def m 将方法 m 添加到类中,remove_method :m 删除 m。但是,如果超类有一个m 方法,那么它仍然会被使用。
undef_method,OTOH,更像是这样的:
class CC < C
def m
raise 'No, you cannot do that.'
end
end
所以undef_method 实际上并没有删除该方法,它用一个特殊的内部标志替换该方法,如果您尝试调用该方法,Ruby 会报错。
听起来您正在尝试替换现有方法,而 replace 在语义上与 remove 后跟 add 相同,所以 @ 987654334@ 可能更合适。但是,如果您想偏执并确保替换方法到位,那么undef_method 会很有用;或者,如果由于某种原因您需要在一个地方删除该方法并将其添加到另一个地方,undef_method 至少会告诉您您只完成了一半的工作,而remove_method 会留下超类的实现(和可能的奇怪错误)或相当混乱的NoMethodError。
【讨论】:
您可以通过两种简单的方式删除方法。剧烈的
Module#undef_method( )
删除所有方法,包括继承的方法。善良的人
Module#remove_method( )
从接收器中删除方法,但它 保留继承的方法。
见下面2个简单的例子-
示例 1 使用 undef_method
class A
def x
puts "x from A class"
end
end
class B < A
def x
puts "x from B Class"
end
undef_method :x
end
obj = B.new
obj.x
结果 -
main.rb:15:in
': undefined methodx' for # (NoMethodError)
使用 remove_method
的示例 2class A
def x
puts "x from A class"
end
end
class B < A
def x
puts "x from B Class"
end
remove_method :x
end
obj = B.new
obj.x
结果 - $ruby main.rb
来自A类的x
【讨论】: