【发布时间】:2012-07-12 17:20:33
【问题描述】:
假设我有一段 Ruby 代码我想为一个方法设置别名(我不知道为什么;假设我有充分的理由)。
class String
alias_method :contains?, :include?
end
在本节之后,我可以删除这个别名吗?
【问题讨论】:
标签: ruby metaprogramming alias-method
假设我有一段 Ruby 代码我想为一个方法设置别名(我不知道为什么;假设我有充分的理由)。
class String
alias_method :contains?, :include?
end
在本节之后,我可以删除这个别名吗?
【问题讨论】:
标签: ruby metaprogramming alias-method
remove_method 在大多数情况下应该可以工作。但如果您的 alias_method 覆盖了现有方法,您可能需要通过单独的 alias_method 调用来保存原始方法。
# assuming :contains? is already a method
alias_method :original_contains?, :contains?
alias_method :contains?, :include?
然后恢复原来的状态:
alias_method :contains?, :original_contains?
remove_method :original_contains? # optional
还要注意,修改在多个线程中使用的类很容易出现竞争条件。如果您试图禁止库使用别名,那么如果您在别名存在时调用这些库的方法,则无法阻止这种情况。我们可能会在 ruby 2.0 中看到一种方法:http://yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-practice/
如果您能说出您想要删除别名的原因,将会很有帮助。如果该方法名称之前不存在,则其他库不应受到猴子补丁的影响。此外,您应该考虑继承 String(或委托给字符串实例)而不是修补 String。
【讨论】:
def hello
puts "Hello World"
end
alias :hi :hello
hi #=> "Hello World"
undef hi
hi #=> NameError
hello #=> "Hello World"
编辑:请注意,这仅适用于在 main 对象上创建的方法。为了在课堂上执行此操作,您需要执行以下操作,Hello.class_eval("undef hi")
但是,从元编程的角度来看,在处理类时,我喜欢使用remove_method :hi,因为它会导致方法查找失败并从父类中获取方法。
class Nums < Array
def include?
puts "Just Kidding"
end
end
n = Nums.new
n << 4 #=> [4]
n.include? #=> "Just kidding"
Nums.class_eval("remove_method :include?")
n.include? 4 #=> true
Number.class_eval("undef include?")
n.include? 4 #=> NoMethodError
remove_method 对元数据更友好。
【讨论】:
remove_method 更好,如果 hi 最初是继承或混合的。使用undef 或undef_method 将阻止调用向上传播继承/混合链。