gpt4 book ai didi

ruby - 优雅的方式添加到已经包含的模块?

转载 作者:数据小太阳 更新时间:2023-10-29 07:00:23 25 4
gpt4 key购买 nike

我想对一个 gem 进行猴子修补,目标代码在一个模块中。不幸的是,在我预先准备我的补丁时,该模块已经包含在各种类中,新代码无效。

例子:

module Feature
def action
puts "Feature"
end
end

module Patch
def action
puts "Patch"
end
end

class Base1
include Feature
end

Feature.prepend Patch

class Base2
include Feature
end


Base1.new.action # Returns "Feature", I want it to be "Patch" instead.
Base2.new.action # Returns "Patch"

当我在 Feature 被包含到 Base2 之前添加前缀时,补丁可以工作,但是对于真正的 gem 我不能改变顺序。

有没有一种优雅的方法可以解决这个问题,还是我必须遍历 ObjectSpace 才能找到哪些类已经包含了 Feature 模块?

最佳答案

TL;DR – 通常不能,但是 Base1.include Patch可能已经足够好了。


对于您的示例代码, ancestors Base1Base2是:(为清楚起见对齐)

Base1.ancestors #=> [Base1,        Feature, Object, Kernel, BasicObject]
Base2.ancestors #=> [Base2, Patch, Feature, Object, Kernel, BasicObject]

Base2有一个额外的祖先Patch之前 FeatureFeature.prepend Patch 的结果.

Ruby 不允许我们随意修改模块的祖先链,所以我们不能只在前面加上 PatchFeature追溯。

但幸运的是,PatchBase 之后的第一个模块类,所以我们可以求助于 include 附加PatchBase1相反:

Base1.include Patch
Base1.ancestors #=> [Base1, Patch, Feature, Object, Kernel, BasicObject]

显然,这只适用于非常特殊的情况,而不适用于一般情况。

这是一个反例:

module Feature
def action ; 'Feature' ; end
end

module Foo
def action ; "#{super} overridden" ; end
end

module Patch
def action ; 'Patch' ; end
end

class Base1
include Feature
include Foo
end

Feature.prepend(Patch)

class Base2
include Feature
include Foo
end

Base1.new.action #=> "Feature overridden"
Base2.new.action #=> "Patch overridden"

Base1.include Patch

Base1.new.action #=> "Patch"

看老祖宗揭示问题:

Base1.ancestors #=> [Base1, Foo,        Feature, Object, Kernel, BasicObject]
Base2.ancestors #=> [Base2, Foo, Patch, Feature, Object, Kernel, BasicObject]
Base1.include Patch
Base1.ancestors #=> [Base1, Patch, Foo, Feature, Object, Kernel, BasicObject]

PatchFoo有问题。

关于ruby - 优雅的方式添加到已经包含的模块?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55090768/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com