Ruby如何延迟扩展方法执行直至类完全加载完成
可行实现方案
不需要把my_method调用移动到类定义末尾,有两种成熟方案可以满足你把调用放在类开头的排版需求:
方案1:通过method_added回调延迟执行检查
核心思路是调用my_method时先不立刻做方法存在性校验,如果目标方法还没定义,就给当前类注册一个方法新增的监听钩子,等目标方法被定义的瞬间再执行校验逻辑,示例代码:
module A def my_method # 目标方法已存在时直接执行逻辑 return puts instance_methods.include?(:my_base_method) if instance_methods.include?(:my_base_method) # 目标方法不存在时注册监听 define_singleton_method(:method_added) do |method_name| next unless method_name == :my_base_method puts instance_methods.include?(:my_base_method) # 执行完成后移除钩子,避免后续新增方法时重复触发 singleton_class.remove_method(:method_added) end end end class B extend A # 直接放在类开头,符合排版要求 my_method def my_base_method end end
运行代码会正常输出true,整个过程不需要调整my_method的书写位置。
方案2:通过TracePoint监听类定义完成事件
如果不想改动原有my_method的核心校验逻辑,可以用Ruby标准库的TracePoint监听类定义结束的事件,等整个类的定义体(包括所有实例方法定义)全部执行完成后,再自动触发校验逻辑,示例代码:
module A def my_method # 监听当前类的end事件,即类定义闭合节点 TracePoint.trace(:end) do |tp| next unless tp.self == self puts self.instance_methods.include?(:my_base_method) # 执行完成后关闭监听,避免内存泄漏 tp.disable end end end class B extend A # 放在类开头即可正常工作 my_method def my_base_method end end
这个方案对原有逻辑的侵入性更低,只需要给my_method加一层事件监听即可,完全不影响原来的方法存在性判断逻辑。
两种方案都不会破坏代码排版,
my_method可以紧跟在extend A语句之后,不需要挪到类定义的末尾位置。
内容的提问来源于stack exchange,提问作者New To Blue
相关产品推荐
相关产品推荐

