题
我还是新的Ruby和整理库珀的书后,基本上只写我的第一个微程序。我指出来避免猴子打补丁的方向,但问题是我不知道有什么办法来实现相同的行为。 基本上,我想添加一个新的方法,它是每一个字符串对象访问。明显的猴修补的方法是:
class String
def do_magic
...magic...
end
end
我记得有使用String.send的方式。但我不记得它是如何做,也没有在那里我阅读。 任何人都可以指出的是,仍然让我提供给String类和子对象的方法其它方法吗?
解决方案
这样做只会是猴子修补一个比较尴尬的语法的任何其他方式。有涉及send
和eval
和各种东西的方式,但为什么的?来吧,做明显的方式。
您要小心大项目猴修补的,或当你有依赖关系,因为你可以与冲突收场时,几只手都在同一个地方瞎搞。这并不意味着看为完成同样的事情的替代语法 - 这意味着要小心,当你正在做的改变,可能会影响代码,这不是你的。这可能不是你的具体情况令人担忧。这只是一些可能需要在较大的项目中加以解决。
在红宝石一种替代方案是可以添加的方法来单个对象。
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
其他提示
如果您想添加一个新的方法,那就是每一个字符串对象访问,然后做它,你必须是如何把它做的方式。
一个好的做法是把你的扩展核心对象在单独的文件(如string_ex.rb
)或子目录(如extensions
或core_ext
)。这样一来,很明显是什么一直延续,并且很容易让别人看到它们是如何扩展或修改。
在哪里猴子补丁可以去坏的是,当你改变了导致预期的原始功能无法正常运作一些其他的代码核心对象存在的一些行为。
在object
类定义send
,并且所有对象继承这一点。你“送”的对象的send
方法。该send
方法的参数是方法,你想学对调用的名称为标志,其次是任何参数和一个可选模块。您还可以使用__send__
。
>> "heya".send :reverse
=> "ayeh"
>> space = %w( moon star sun galaxy )
>> space.send(:collect) { |el| el.send :upcase! }
=> ["MOON", "STAR", "SUN", "GALAXY"]
修改.. 强>
您可能需要使用该方法define_method
:
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
您无法定义期望的块虽然方法。
这可能是一件好事,有一个读从为什么的凄美指南本章一>,您可以向下跳到“Dwemthy的阵列”去的元编程的东西。
由于球员。
所有建议的落实工作。更重要的是,我学会了在手的情况下权衡,并决定是否重开核(或库)班是一个好主意或没有。
FWIW,有朋友指出send
实现我一直在寻找。但现在,我看它,它甚至更接近的Monkeypatching比其他所有实现:)
module M
def do_magic
....
end
end
String.send(:include, M)
作为替代附接功能的类或对象,可以随时去官能路线:
class StringMagic
def self.do(string)
...
end
end
StringMagic.do("I'm a String.") # => "I'm a MAGIC String!"
在“猴子补丁”你的描述确实可以是一个问题,如果别人想需要你的代码(如宝石,例如)。谁是说,他们不会也想补充一点,被称为do_magic一个字符串的方法?一种方法将覆盖其他的,这可以是具有挑战性的调试。如果有任何机会,你的代码是开源的,那么最好是创建自己的类:
class MyString < String
def initialize(str)
@str = str
end
def do_magic
...magic done on @str
@str
end
end
现在,如果你需要do_magic您可以
magic_str = MyString.new(str).do_magic