Ruby 覆盖用#define_singleton_方法定义的实例方法并调用original

Ruby 覆盖用#define_singleton_方法定义的实例方法并调用original,ruby,Ruby,我有一个类,它在它的实例上动态地定义方法,如下所示 obj = Object.new obj.define_singleton_method(:foo) { "foo" } 稍后,我想重新定义#foo,但可以调用原始实现 当使用普通类时,这可以通过prepend MyModule和在prepend方法内调用super来实现。但是,#prepend在实例级别不可用 我用#extend尝试了它,但它似乎根本没有覆盖#foo方法: obj = Object.new obj.define_single

我有一个类,它在它的实例上动态地定义方法,如下所示

obj = Object.new
obj.define_singleton_method(:foo) { "foo" }
稍后,我想重新定义
#foo
,但可以调用原始实现

当使用普通类时,这可以通过
prepend MyModule
和在prepend方法内调用
super
来实现。但是,
#prepend
在实例级别不可用

我用
#extend
尝试了它,但它似乎根本没有覆盖
#foo
方法:

obj = Object.new
obj.define_singleton_method(:foo) { "foo" }
mod = Module.new
mod.define_method(:foo) { "module foo" }
obj.extend(mod)
obj.foo
# => "foo"
我研究了RSpec gem,因为它们实现了与
#和_wrap_original
(请参见)类似的行为,但我不在测试环境中,实现这种行为需要很多设置代码(跟踪存根,在重置存根时进行回调等)


那么,你知道如何在纯Ruby中实现这一点吗?

请查看
obj.singleton\u class.祖先
,看看实际发生了什么。默认情况下,它类似于

[#<Class:#<Object:0x00007febcf103160>>, Object, Kernel, BasicObject]
所以顺序不好,因为模块“落后于”单例类。为了替换它,它需要在祖先链中的较早位置。您可以通过
obj.singleton\u class.prepend(mod)
来实现这一点。在这种情况下,祖先链是:

[#<Module:0x00007febcd0bb088>, #<Class:#<Object:0x00007febcf103160>>, Object, Kernel, BasicObject]
[#<Module:0x00007febcd0bb088>, #<Class:#<Object:0x00007febcf103160>>, Object, Kernel, BasicObject]
obj.foo
# => "module foo"