“我该如何清洁?”;“重新连接”;Ruby中的分离方法?
假设我有这门课:“我该如何清洁?”;“重新连接”;Ruby中的分离方法?,ruby,Ruby,假设我有这门课: class Foo def destroy_target(target) Missile.launch(target) end end 我想暂时消除Foo的破坏力,例如用于测试目的,所以我这样做: backup = Foo.instance_method(:destroy_target) class Foo def destroy_target(target) Pillow.launch(target) end end 我的问题是:如何将原
class Foo
def destroy_target(target)
Missile.launch(target)
end
end
我想暂时消除Foo
的破坏力,例如用于测试目的,所以我这样做:
backup = Foo.instance_method(:destroy_target)
class Foo
def destroy_target(target)
Pillow.launch(target)
end
end
我的问题是:如何将原始方法“重新附加”到Foo
,就好像它一开始从未被重写一样
我意识到我可以做到这一点:
class Foo
def destroy_target(target)
backup.bind(self).call(target)
end
end
但显然这不是最优的,因为我现在正在包装原始函数。我希望能够无限次地分离和重新连接该方法,而不增加任何开销
用另一种方式问;如何将DetachedMethod
正确地附加到类,即不定义调用分离方法的新方法
注意:我对临时更改类功能的其他方法不感兴趣。我特别想知道如何用不同的方法替换一个方法,然后干净地恢复原始方法。这似乎有效:
Foo.instance_exec {
define_method(:destroy_target, backup)
}
但我不完全确定这是否没有副作用。如果有人确实知道的话,我将非常感谢你的评论
如果Foo
是这样定义的一个模块,那么这似乎也可以工作:
module Foo
extend self
def destroy_target(target)
Missile.launch(target)
end
end
我测试了您的第一个示例,它似乎运行良好。我没有发现任何副作用,但这并不意味着没有副作用 你考虑过了吗? 上课 它可能会带来比您的示例更标准、更容易理解的优势 对于模块 如果
Foo
是一个模块
,您不能直接调用refine Foo
,您将得到一个TypeError:错误的参数类型模块(预期类)
但是,您可以优化它的单例类
:
module Foo
def self.destroy_target(target)
Missile.launch(target)
end
end
module PillowLauncher
refine Foo.singleton_class do
def destroy_target(target)
Pillow.launch(target)
end
end
end
module Test
using PillowLauncher
Foo.destroy_target('Tatooine')
#=> PILLOW -> Tatooine
end
Foo.destroy_target('Tatooine')
#=> MISSILE -> Tatooine
我不确定你的笔记:
我对临时改变的其他方式不感兴趣
类的功能。我特别想知道如何
用其他方法替换一个方法,然后恢复原始方法
方法干净
我建议的代码似乎两者都能做到。
backup=Foo.instance\u方法(:destroy\u target)
没有s
你想为一个特定的Foo
实例或类范围(即所有Foo
s)替换方法吗?定义方法
似乎正确,但我会使用Foo.send(:define_method,:destroy_target,backup)
–它看起来没有那么侵入性。改进看起来很酷,但显然它们只适用于类(而不是模块)。在我当前的用例中,我需要它来处理模块。在Ruby版本2.3之前,它们还必须在顶级激活,也就是说,正如您所演示的,它们不能在类或模块内激活。我用2.1.5和2.2.1测试了这段代码。我实际上对它的工作感到惊讶,因为文档只提到了顶级的改进。
module Foo
def self.destroy_target(target)
Missile.launch(target)
end
end
module PillowLauncher
refine Foo.singleton_class do
def destroy_target(target)
Pillow.launch(target)
end
end
end
module Test
using PillowLauncher
Foo.destroy_target('Tatooine')
#=> PILLOW -> Tatooine
end
Foo.destroy_target('Tatooine')
#=> MISSILE -> Tatooine