我正在为 Rails (6.1.7) 项目 Foreman(v3.5.1;基于 Foreman 插件模板)开发一个 插件,并面临我的一个模块 (
DnsInterfaceExtensions
) 的问题) 应该放在 Foreman 模块前面。问题是,即使在 prepend
之后,DnsInterfaceExtensions
也不会 not 显示为 Foreman 的 DnsInterface
的祖先(在 Rails 控制台中):
irb(main):001:0> DnsInterface.ancestors
=> [DnsInterface]
irb(main):002:0> DnsInterface.prepend ForemanCnames::Concerns::DnsInterfaceExtensions
=> DnsInterface
irb(main):003:0> DnsInterface.ancestors
=> [DnsInterface]
irb(main):005:0> DnsInterface.prepend Module.new
=> DnsInterface
irb(main):006:0> DnsInterface.ancestors
=> [#<Module:0x0000558ef346d9d0>, DnsInterface]
我尝试定义
DnsInterfaceExtensions#prepended
,显然它被执行了,但是新的类方法没有添加到DnsInterface
,模块的常量:RECORD_TYPE
覆盖也没有。如果 Ruby 没有任何错误,我不知道这个结果的原因是什么。有什么想法吗?
感谢您的宝贵时间,
泽维尔。
编辑-1
我刚刚发现任何延伸的空心模块都会出现同样的现象
ActiveSupport::Concern
?
irb(main):001:0> (DnsInterface.prepend Module.new { extend ActiveSupport::Concern }).ancestors
=> [DnsInterface]
编辑-2
然而,在这个SO回答中,@Marian13说Rails 6.1.7应该支持前置。然而,当两个模块扩展ActiveSupport::Concern
时,它不起作用
。
irb(main):001:1* module M
irb(main):002:1* extend ActiveSupport::Concern
irb(main):003:0> end
=> M
irb(main):004:1* module N
irb(main):005:1* extend ActiveSupport::Concern
irb(main):006:0> end
=> N
irb(main):007:0> (M.prepend N).ancestors
=> [M]
但是,如果不在我的模块中扩展 ActiveSupport::Concern
,我就无法使用
prepended
或
class_methods
块。
我想这整个事情都会出错,因为
Concern的class_methods
:ClassMethods
。因此,通过在两个模块中扩展
ActiveSupport::Concern
,每个模块都有自己的
:ClassMethods
,以某种方式阻止建立祖先?
ActiveSupport::Concern
的预感是正确的。通过模仿 Concern 的语法糖,在前面添加一个名为
ClassMethods
的嵌套模块 not,事情会变得更好。
module ForemanCnames::DnsInterfaceExtensions
def self.prepended(base)
class << base
prepend CnameClassMethods
end
end
module CnameClassMethods
def dns_cname_record_attrs
end
end
end
irb(main):001:0> DnsInterface.ancestors
=> [ForemanCnames::DnsInterfaceExtensions, DnsInterface]
irb(main):002:0> DnsInterface.methods.filter { |m| m.to_s =~ /cname/ }
=> [:dns_cname_record_attrs]
虽然我没能覆盖常量。
irb(main):003:0> DnsInterface::RECORD_TYPES
=> [:a, :aaaa, :ptr4, :ptr6]
...但这是一个不同的问题。
我想我必须撤回这个答案,因为它没有达到我想要的......
irb(main):001:0> DnsInterface.method(:dns_feasible?).source_location
=> ["/usr/local/share/gems/gems/foreman_cnames-0.0.1/app/models/foreman_cnames/dns_interface_extensions.rb", 15]
irb(main):002:0> DnsInterface.instance_method(:dns_feasible?).source_location
=> ["/usr/share/foreman/app/models/concerns/dns_interface.rb", 22]
虽然添加了 DnsInterfaceExtension
的方法,但它们并没有覆盖
DnsInterface
已有的内容。