Ruby类加载后动态包含模块链的调用问题求助
解决类加载完成后动态扩展模块的问题
首先我们来拆解一下你遇到的问题:
当你在Ab类定义完成后执行B.send(:include, A),虽然模块B现在包含了A的方法,但因为你使用了ActiveSupport::Concern,Ab在include B时已经将当时B的实例方法直接注入到自身的实例方法集合中,Ruby不会自动回溯更新已经包含过该模块的类,所以Ab的实例无法找到后续新增的method_a方法。
下面提供几种无需调整代码顺序的解决方案:
方案1:手动将模块A注入目标类
既然B已经扩展了A,你可以直接把A包含到Ab类中,让Ab的实例获取method_a:
require 'active_support/concern' module A extend ActiveSupport::Concern def method_a puts "Method_a" end end module B extend ActiveSupport::Concern def method_b puts "Method_b" end end class Ab include B def calltest method_a method_b end end B.send(:include, A) # 直接将A包含到Ab中 Ab.include(A) Ab.new.method_a # 输出 Method_a Ab.new.method_b # 输出 Method_b
方案2:用钩子自动同步所有依赖类
如果有多个类都包含了B,不想逐个手动处理,可以给B添加一个钩子,记录所有包含它的类,之后批量更新这些类:
require 'active_support/concern' module A extend ActiveSupport::Concern def method_a puts "Method_a" end end module B extend ActiveSupport::Concern # 存储所有包含过B的类 @@included_classes = [] # 当类包含B时,自动记录该类 included do |base| @@included_classes << base end def method_b puts "Method_b" end # 批量同步所有已包含B的类 def self.sync_extensions @@included_classes.each do |klass| klass.include(A) end end end class Ab include B def calltest method_a method_b end end B.send(:include, A) # 触发同步操作 B.sync_extensions Ab.new.method_a # 正常运行 Ab.new.method_b # 正常运行
方案3:改用普通模块(如果允许)
如果你的场景不需要ActiveSupport::Concern的特性(比如模块间的依赖管理、类方法注入),可以去掉extend ActiveSupport::Concern,改用普通模块。此时Ruby的方法查找链会自动处理模块的后续扩展,无需额外操作:
module A def method_a puts "Method_a" end end module B def method_b puts "Method_b" end end class Ab include B def calltest method_a method_b end end B.send(:include, A) Ab.new.method_a # 正常输出 Method_a Ab.new.method_b # 正常输出 Method_b
内容的提问来源于stack exchange,提问作者Selvamani
相关产品推荐
相关产品推荐

