ruby - Ruby 2.6:如何在添加模块时动态覆盖实例方法?
问题描述
我有一个名为Notifier
.
module Notifier
def self.prepended(host_class)
host_class.extend(ClassMethods)
end
module ClassMethods
def emit_after(*methods)
methods.each do |method|
define_method(method) do |thing, block|
r = super(thing)
block.call
r
end
end
end
end
end
它公开了一个类方法emit_after
。我像这样使用它:
class Player
prepend Notifier
attr_reader :inventory
emit_after :take
def take(thing)
# ...
end
end
目的是通过调用emit_after :take
,模块#take
用自己的方法覆盖。
但是实例方法没有被覆盖。
但是,我可以在不使用的情况下明确覆盖它ClassMethods
module Notifier
def self.prepended(host_class)
define_method(:take) do |thing, block|
r = super(thing)
block.call
r
end
end
class Player
prepend Notifier
attr_reader :inventory
def take(thing)
# ...
end
end
#> @player.take @apple, -> { puts "Taking apple" }
#Taking apple
#=> #<Inventory:0x00007fe35f608a98...
我知道它ClassMethods#emit_after
被调用了,所以我假设该方法正在被定义,但它永远不会被调用。
我想动态创建方法。如何确保生成方法覆盖我的实例方法?
解决方案
@Konstantin Strukov
的解决方案很好,但可能有点混乱。所以,我建议另一种解决方案,它更像原来的解决方案。
您的第一个目标是为您的类添加一个类方法( emit_after
)。为此,您应该使用extend
不带任何钩子的方法,例如self.prepended()
,self.included()
或self.extended()
.
prepend
, 以及include
, 用于添加或覆盖实例方法。但这是你的第二个目标,它发生在你打电话时emit_after
。所以你不应该使用prepend
orinclude
扩展你的课程。
module Notifier
def emit_after(*methods)
prepend(Module.new do
methods.each do |method|
define_method(method) do |thing, &block|
super(thing)
block.call if block
end
end
end)
end
end
class Player
extend Notifier
emit_after :take
def take(thing)
puts thing
end
end
Player.new.take("foo") { puts "bar" }
# foo
# bar
# => nil
现在很明显,您调用extend Notifier
是为了添加emit_after
类方法,所有的魔法都隐藏在方法中。
推荐阅读
- javascript - 使用自定义 React 钩子提交带有数据的表单
- php - 如何在刀片 Laravel 中添加两个数字
- mysql - MySQL Workbench 不会连接到 AWS RDS DB。错误 - “无法连接到本地主机”
- spring-boot - WebClient 5.3+ 交换与 exchangeToMono。一起提取 cookie 和 body
- android - Android中的Delphi TEdit - 在每个TEdit的基础上关闭自动上限
- json - CI管道失败,即使它正在做它应该做的事情
- c# - 选项卡视图在 UWP Windows UI 库上无法正常工作
- c++ - 仅当在 Visual Studio C++ MFC 桌面应用程序上使用 64 位 (x64) 构建平台时,链接的 DLL 之间才会出现 LNK 2001 和 LNK 2019 错误
- flutter - 在颤动中使用 path_provider 的路径无效?
- mysql - N对N关系选择