Внутренняя система плагинов и модули в Ruby (Rails используется в качестве фреймворка) - PullRequest
1 голос
/ 03 апреля 2019

Я хочу создать базовую девочку, а затем загрузить все подклассы (плагины) и обработать их все через цикл 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

В сети существуют другие типы примеров плагинов, но они должны инициализироваться по одному. Этот пример кода загружает все плагины и выполняет один и тот же метод во всех них. Мне нужен этот функционал с модулями.

1 Ответ

1 голос
/ 03 апреля 2019
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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...