Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby monkey修补核心类的替代方案_Ruby_Oop_Monkeypatching - Fatal编程技术网

Ruby monkey修补核心类的替代方案

Ruby monkey修补核心类的替代方案,ruby,oop,monkeypatching,Ruby,Oop,Monkeypatching,我对Ruby还是一个新手,基本上刚刚写完库珀的书,写了我的第一个微程序。我被指向了避免猴子修补的方向,但问题是我不知道实现相同行为的替代方案是什么。 基本上,我想添加一个每个string对象都可以访问的新方法。显而易见的猴子修补方法是: class String def do_magic ...magic... end end 我记得有一种使用String.send的方法。但我不记得是怎么做的,也不记得在哪里读的。 有谁能指出一些替代方法,让我仍然可以将该方法用于String类

我对Ruby还是一个新手,基本上刚刚写完库珀的书,写了我的第一个微程序。我被指向了避免猴子修补的方向,但问题是我不知道实现相同行为的替代方案是什么。 基本上,我想添加一个每个string对象都可以访问的新方法。显而易见的猴子修补方法是:

class String
  def do_magic
    ...magic...
  end
end
我记得有一种使用String.send的方法。但我不记得是怎么做的,也不记得在哪里读的。
有谁能指出一些替代方法,让我仍然可以将该方法用于String类和子对象吗?

对于monkey patching来说,任何其他方法都是一种更笨拙的语法。有很多方法包括
send
eval
以及各种各样的事情,但是为什么呢?去吧,用显而易见的方式去做

在大型项目中或当您有依赖关系时,您需要小心猴子补丁,因为当几只手在同一个地方乱搞时,您可能会遇到冲突。这并不意味着寻找一种替代的语法来完成同样的事情——这意味着在进行可能会影响不属于您的代码的更改时要小心。在你的特殊情况下,这可能不是一个问题。这只是一些可能需要在大型项目中解决的问题

Ruby中的另一种选择是,可以向单个对象添加方法

a = "Hello"
b = "Goodbye"
class <<a
  def to_slang
    "yo"
  end
end
a.to_slang # => "yo"
b.to_slang # NoMethodError: undefined method `to_slang' for "Goodbye":String
a=“你好”
b=“再见”

类对象
类定义
send
,所有对象都继承该类。您可以使用
send
方法“发送”对象。
send
方法的参数是您要调用的方法,该方法的名称作为符号,后跟任何参数和可选块。您也可以使用
\uuuuu发送\uuuuuu

>> "heya".send :reverse
=> "ayeh"

>> space = %w( moon star sun galaxy )
>> space.send(:collect) { |el| el.send :upcase! }
=> ["MOON", "STAR", "SUN", "GALAXY"]
编辑..

您可能希望使用
define\u方法
方法:

String.class_eval {
  define_method :hello do |name|
    self.gsub(/(\w+)/,'hello') + " #{name}"
  end
}

puts "Once upon a time".hello("Dylan")
# >> hello hello hello hello Dylan
这增加了实例方法。要添加类方法,请执行以下操作:

eigenclass = class << String; self; end
eigenclass.class_eval {
  define_method :hello do
    "hello"
  end
}

puts String.hello
# >> hello
eigenclass=class>hello
但是,您不能定义需要块的方法


阅读可能是一件好事,你可以跳到“Dwemthy的数组”来了解元编程的内容。

如果你想添加一个每个字符串对象都可以访问的新方法,那么按照你现有的方式来做就是如何完成它

一个好的做法是将核心对象的扩展名放在单独的文件(如
string\u ex.rb
)或子目录(如
extensions
core\u ext
)中。通过这种方式,很明显是什么被扩展了,人们很容易看到他们是如何被扩展或改变的

monkey patching可能出现问题的地方是,当您更改核心对象的某些现有行为时,会导致一些其他代码期望原始功能出现错误。

谢谢大家

所有建议的实施工作。更重要的是,我学会了权衡手头的案例,并决定是否重新打开核心(或库)类是一个好主意

FWIW,一位朋友指出了我正在寻找的
send
实现。但现在我看了一下,它比其他所有实现更接近monkeypatching:)


作为将函数附加到类或对象的替代方法,您可以始终按照函数路径:

class StringMagic
  def self.do(string)
     ...
  end
end

StringMagic.do("I'm a String.") # => "I'm a MAGIC String!"
如果其他人需要您的代码(例如gem),那么您描述的“猴子补丁”可能确实是个问题。谁说他们不想添加一个名为do_magic的字符串方法?一种方法将覆盖另一种方法,这对调试来说是一个挑战。如果您的代码有可能是开源的,那么最好创建您自己的类:

class MyString < String
  def initialize(str)
    @str = str
  end
  def do_magic
    ...magic done on @str
    @str
  end
end

我可以看出这实际上取决于项目本身的情况和性质。我认为这也适用于所有的做/不做对。考虑到我的特殊情况,是的,这是有道理的,它不应该伤害。毕竟,我正在添加一种新方法。谢谢你的澄清!猴子修补是一个滑坡,最多。对于封闭源代码项目中的小型团队来说,这可能看起来很优雅,但您永远不知道什么时候您的源代码可能会打包为gem或被其他人复制,如果他们希望他们的字符串以稍微不同的方式发挥作用,那么一个猴子补丁的方法将覆盖另一个,并且不会抛出任何警告。这是一个很难找到的错误食谱。如果要覆盖Ruby中包含的基类的方法,问题就更大了。我当时正试图暂时避免跳入元编程。但我想这是不可避免的,如果我想通过hello world的东西。我关于使用evals的想法基本上是运行时修补程序。但我现在明白了,其他一切都是这样。
class MyString < String
  def initialize(str)
    @str = str
  end
  def do_magic
    ...magic done on @str
    @str
  end
end
magic_str = MyString.new(str).do_magic