I'm working on a tool that provides common functionality in a class (call it Runner
) and that can invoke user-defined code using a kind of plugin system. For any execution of the tool, I need to dynamically execute various methods defined by one or more plugins. Because the Runner
class defines many instance-level attributes that will be needed in the plugins, I would like to execute the plugin methods as if they were instance methods of Runner
.
Here is a simplified example:
module Plugin1
def do_work
p ['Plugin1', data]
end
end
module Plugin2
def do_work
p ['Plugin2', data]
end
end
module Plugin3
def do_work
p ['Plugin3', data]
end
end
class Runner
attr_accessor :data # Plugins need access to these.
def initialize(data, *plugins)
@data = data
@plugin_names = plugins.map { |p| "Plugin#{p}" }
end
def run
@plugin_names.each { |name|
mod = Kernel.const_get(name)
plugin_method = mod.instance_method(:do_work)
# How do I call the plugin_method as if it were
# an instance method of the Runner?
}
end
end
# Execute a runner using Plugin3 and Plugin1.
r = Runner.new(987, 3, 1)
r.run
I have experimented with various ways to pull this off using instance_exec
, bind
, module_function
, and so forth, but haven't gotten anything to work. I'm open to other approaches for the tool, of course, but I'm also curious whether this can be done in the manner described above.