根据维基百科,monkey patch是:
一种扩展或修改运行时的方法 动态语言代码[...] 不改变原始来源 代码。
同一条目中的以下陈述使我感到困惑:
在Ruby中,猴子补丁一词是 被误解为任何动态 经常修改课程 用作动态的同义词 在运行时修改任何类。
我想知道在Ruby中修补猴子的确切含义。它是在执行类似下面的操作,还是其他内容?
class String
def foo
"foo"
end
end
答案 0 :(得分:62)
我听到的最好的解释是猴子修补/鸭子打击是由Patrick Ewing在RailsConf 2007
......如果它像鸭子一样走路,像鸭子一样说话,它就是一只鸭子,对吗?所以 如果这只鸭子没有给你你想要的噪音,你必须这样做 只要打一下鸭子,直到它恢复你想要的效果。
答案 1 :(得分:44)
简短的回答是,没有“确切”的含义,因为它是一个新颖的术语,不同的人使用它的方式不同。至少可以从维基百科的文章中看出这一点。有些人坚持认为它只适用于“运行时”代码(我猜想是内置类),而有些人会用它来引用任何类的运行时修改。
就个人而言,我更喜欢更具包容性的定义。毕竟,如果我们只使用术语修改内置类,我们如何引用所有其他类的运行时修改?对我来说重要的是源代码和实际运行类之间存在差异。
在Ruby中,猴子补丁一词是 被误解为任何动态 经常修改课程 用作动态的同义词 在运行时修改任何类。
上面的陈述断言Ruby的用法不正确 - 但是术语发展了,这并不总是坏事。
答案 2 :(得分:19)
Monkey修补是指在运行时替换类的方法(不添加新方法,就像其他人所描述的那样)。
除了作为一种非常明显且难以调试的方式来改变代码之外,它还不能扩展;随着越来越多的模块启动猴子修补方法,变化的可能性会相互增加。
答案 3 :(得分:4)
你是对的;当你修改或扩展现有的类而不是它的子类时。
答案 4 :(得分:3)
这是猴子补丁:
class Float
def self.times(&block)
self.to_i.times { |i| yield(i) }
remainder = self - self.to_i
yield(remainder) if remainder > 0.0
end
end
现在我想象这有时可能会有用,但想象一下你是否看过常规。
def my_method(my_special_number)
sum = 0
my_special_number.times { |num| sum << some_val ** num }
sum
end
当它被调用时,它只会偶尔打破 。对于那些关注你已经知道原因,但想象你不知道具有.times
类方法的float类型,并且你自动假设my_special_number
是一个整数。每次参数是整数,整数或浮点数时,它都可以正常工作(除非存在浮点余数,否则会传回整个整数)。但是传递一个带有小数区域内任何数字的数字,它肯定会中断!
想象一下你的宝石,Rails插件,甚至你自己的同事在你的项目中可能会发生多少次。如果这里有一两个小方法,可能需要一些时间才能找到并纠正。
如果你想知道它为什么会中断,请注意sum
是一个整数,可以传回一个浮点余数;此外,指数符号仅在类型相同时才有效。所以你可能认为它是固定的,因为你把烦恼的数字转换为浮点数......只是发现总和不能得到浮点结果。
答案 5 :(得分:2)
在Python中,monkeypatching被大量引用作为尴尬的标志:“我不得不monkeypatch这个类,因为......”(我在处理Zope时首先遇到它,文章提到)。它曾经说过,有必要抓住一个上游类并在运行时修复它,而不是游说,以便在实际类中修复不需要的行为或将它们固定在子类中。根据我的经验,Ruby人不会谈论monkeypatching那么多,因为它不被认为特别糟糕甚至值得注意(因此“鸭子打孔”)。显然,您必须小心改变将在其他依赖项中使用的方法的返回值,但是以与active_support和facet相同的方式向类添加方法是非常安全的。
10年后更新:我会修改最后一句话,说“相对安全”。如果其他人获得相同的想法并使用不同的实现或方法签名添加相同的方法,或者如果人们混淆核心语言功能的扩展方法,则使用新方法扩展核心库类可能会导致问题。这两种情况经常发生在Ruby中(特别是关于active_support方法)。
答案 6 :(得分:1)
通常它意味着使用Ruby开放类进行临时更改,通常使用低质量代码。
关于这个问题的良好跟进:
http://www.infoq.com/articles/ruby-open-classes-monkeypatching
答案 7 :(得分:0)