有重新定义红宝石方法的问题

时间:2011-03-09 10:36:07

标签: ruby

在Ruby中重新定义方法时要注意哪些事项?重新定义核心库方法还行吗?

5 个答案:

答案 0 :(得分:2)

问题恕我直言

  • 你会忘记改变。
  • 你将复制从互联网上粘贴一个片段,这会触发改变行为的错误,你会抓住你的头,直到你得到无毛的补丁。
  • 另一名开发人员会在你的3个月之后跟踪你的一个错误,直到他发现它在一个猴子补丁中。他会去人力资源部,获取你的地址,并告诉你为什么不做猴子补丁。

现在,有时你需要修补一个类(即使在核心库中,为什么不呢)。我的建议是

  • 将所有猴子补丁放在一个源文件夹中。
  • 在“Hello my name is ...”之后,您对新开发人员说的第二件事是该文件夹的位置以及每个猴子补丁的功能的详细说明。

答案 1 :(得分:2)

我自己并没有做太多的monkeypatching,但我听说过而不是做

class String
  def improved_method
    # teh codes
  end
end

最好将新方法放入模块中,然后包含模块

module ImprovedString
  def improved_method
    # teh codes
  end
end

class String
  include ImprovedString
end

它可以更容易地找到定义方法的位置,并且旧版本仍然存在而无需进行别名链接。

答案 2 :(得分:1)

我喜欢其他答案。但是,我必须补充一点:

有时您可能只想为某些实例重新定义方法。你可以做到这一点,它使得它在某种程度上比改变某个类的所有对象的功能更有效 - 只要使用适当的调试器进行调试:

class << object_instance
  def method_redefinition
    return "method_redefinition"
  end
end
object_instance.method_redefinition => "method redefinition"

所提到的一组功能也可以封装在一个混合中,以避免过多的嵌套和杂乱的“代码执行中的代码定义”:

module M
  def method_redefinition
     "method_redefinition"
  end
end
object_instance.extend M
object_instance.method_redefinition => "method_redefinition"

答案 3 :(得分:0)

你在谈论猴子修补,根据wikipedia

,由于以下原因这很危险
  

粗心写作或写得不好   有记录的猴子补丁可以导致   问题:

     
      
  • 当补丁做出假设时,它们可能导致升级问题   已修补的对象不再存在   真正;如果您更改了产品   它可能会在新版本中发生变化   好好打破你的补丁。为此原因   经常制作猴子补丁   有条件的,仅适用于   合适的。
  •   
  • 如果两个模块尝试使用相同的方法进行猴子补丁,则其中一个   他们(无论哪一个跑到最后)“赢”   而另一个补丁没有效果,   除非使用monkeypatches   模式如alias_method_chain
  •   
  • 它们在磁盘上的原始源代码之间产生差异   可以观察到的行为   对任何不知道的人都很困惑   补丁的存在。
  •   
     

即使不使用猴子补丁,   有些人看到了问题   功能的可用性,因为   使用猴子修补的能力   编程语言不兼容   强制封装,   根据对象能力的要求   模型,在对象之间。

有人谈论更安全的猴子方式 补丁进入红宝石2召唤 refinements

答案 4 :(得分:0)

如果你发现自己遇到了猴子修补问题,这个小小宝石可能会有用:(https://github.com/gnovos/ctx)。我最初编写它是为了创建更具表现力的DSL,允许更改基础对象而不会在其他地方造成太大的损害,但它可能会被用于任何数量的用途。它通过将方法重新定义为可以根据需要换出的任意上下文来解决一些猴子修补问题。

如果我想在某个核心类中重新定义一个方法(例如,在String等中),我使用ctx_define而不是“def”,然后在ctx块中包含应该使用新定义的代码部分,像这样:

class ::String
  ctx_define :dsl, :+ do |other|
    "#{self[0].upcase}#{self[1..-1]}#{other.capitalize}"
  end
end

puts "this" + "is" + "normal" + "text" + "concatination"
# => thisisnormaltextconcatination

ctx(:dsl) { puts "this" + "is" + "special" + "text" + "concatination" }
# => ThisIsSpecialTextConcatination

我只在几分钟内把它扔在一起,所以我无法保证它在任何复杂情况下的稳健性,但它似乎可以很好地满足简单的需求。如果您有兴趣,请查看它是否有任何帮助。 :)