我想创建一个基础类,然后加载所有子类(插件)并通过each
循环处理它们。这是工作示例:
require 'set'
class Plugin
# Keep the plugin list inside a set so we don't double-load plugins
@plugins = Set.new
def self.plugins
@plugins
end
def self.register_plugins
# Iterate over each symbol in the object space
Object.constants.each do |klass|
# Get the constant from the Kernel using the symbol
const = Kernel.const_get(klass)
# Check if the plugin has a super class and if the type is Plugin
if const.respond_to?(:superclass) and const.superclass == Plugin
@plugins << const
end
end
end
end
class DogPlugin < Plugin
def self.handle_command(cmd)
p "Command received #{cmd}"
end
end
class CatPlugin < Plugin
def self.handle_command(cmd)
p "Command received #{cmd}"
end
end
Plugin.register_plugins
# Test that we can send a message to each plugin
Plugin.plugins.each do |plugin|
plugin.handle_command('test')
end
此代码示例完美运行。输出为:
"Command received test"
"Command received test"
=> #<Set: {DogPlugin, CatPlugin}>
但是,在我的rails应用程序中,我的自定义实现位于模块中。可以说我有一个A
模块。在这种情况下,它不起作用。
require 'set'
module A
class Plugin
@plugins = Set.new
class << self
attr_reader :plugins
end
def self.register_plugins
# Iterate over each symbol in the object space
Object.constants.each do |klass|
# Get the constant from the Kernel using the symbol
const = Kernel.const_get(klass)
# Check if the plugin has a super class and if the type is Plugin
if const.respond_to?(:superclass) && (const.superclass == A::Plugin)
@plugins << const
end
end
end
end
end
module A
class MyAction < Plugin
def self.handle_command(cmd)
puts "Command received #{cmd}"
end
end
end
A::Plugin.register_plugins
A::Plugin.plugins.each do |plugin|
plugin.handle_command('test')
end
Set
为空,没有任何执行。为什么?
在此处查看实时示例:https://repl.it/repls/EllipticalDamagedCategory
网络上还有其他类型的插件示例,但它们必须一个接一个地初始化。此示例代码将加载所有插件并在所有插件中执行相同的方法。我需要模块具有此功能。
答案 0 :(得分:1)
require 'set'
module A
class Plugin
@plugins = Set.new
def self.plugins
@plugins
end
def self.register_plugins
# Iterate over each symbol in the object space
::A.constants.each do |klass|
# Get the constant from the Kernel using the symbol
const = A.const_get(klass)
puts const
# Check if the plugin has a super class and if the type is Plugin
if const.respond_to?(:superclass) && (const.superclass == Plugin)
@plugins << const
end
end
end
end
end
module A
class MyAction < Plugin
def self.handle_command(cmd)
puts "Command received #{cmd}"
end
end
end
A::Plugin.register_plugins
A::Plugin.plugins.each do |plugin|
plugin.handle_command('test')
end