Ruby中include模块后触发undefined method错误求助
问题原因
你代码报错的核心原因是:include Callback会把模块中的add_callback方法添加为TaskManager的实例方法,但你是在TaskManager类定义的顶层(类上下文)调用add_callback,这相当于尝试调用TaskManager的类方法,二者不在同一个方法层面,所以会提示undefined method。
另外还有一个隐藏问题:你调用add_callback时传了3个参数,但原模块的add_callback只接收1个参数,即使解决了方法层面的问题,也会触发参数数量不匹配的错误。
解决方案
下面提供两种可行的修改方式,任选其一即可:
方式一:用extend替换include
extend会把模块中的方法直接添加为类的类方法,刚好匹配你在类上下文调用的需求,同时修改模块支持多参数:
修改Callback模块
module Callback # 改为接收可变参数,支持一次性传入多个符号 def add_callback(*names) names.each do |name| define_method(name) do instance_variable_get("@#{name.to_s}") end define_method("#{name.to_s}=") do |value| instance_variable_set("@#{name.to_s}", value) end end end end
修改TaskManager类
把include Callback改成extend Callback即可:
require_relative "./callback" class TaskManager extend Callback add_callback :on_start, :on_finished, :on_error def initialize; end end
方式二:利用模块的included钩子(更符合Ruby惯用写法)
如果希望保留include的语义(比如后续可能给TaskManager实例添加其他模块方法),可以通过included钩子,在模块被include时自动把add_callback注入为类方法:
修改Callback模块
module Callback # 当模块被include时触发该钩子 def self.included(base) # 将ClassMethods模块中的方法添加为base类(即TaskManager)的类方法 base.extend(ClassMethods) end # 单独定义类方法模块 module ClassMethods def add_callback(*names) names.each do |name| define_method(name) do instance_variable_get("@#{name.to_s}") end define_method("#{name.to_s}=") do |value| instance_variable_set("@#{name.to_s}", value) end end end end end
TaskManager类无需修改
保持原来的include Callback即可:
require_relative "./callback" class TaskManager include Callback add_callback :on_start, :on_finished, :on_error def initialize; end end
内容的提问来源于stack exchange,提问作者Dedy Puji
相关产品推荐
相关产品推荐

