Архитектура плагина Ruby

Мне нужен очень простой пример крошечной базовой программы, которая читается в двух плагинах и регистрирует их. Эти два плагина соединяются в базовую программу тем же самым способом без надобности.

Я очень новичок в метапрограммировании на любом языке программирования, но не знаю, с чего начать.

Ответ 1

Я уже давно работаю над этой проблемой. я попробовал несколько разных способов сделать это и попросил совета у многих людей. я все еще не уверен, что у меня есть "правильный путь", но он работает хорошо и легко сделать.

в моем случае, я специально рассматриваю конфигурацию и приношу плагины конфигурации, но принцип тот же, даже если терминология для моей специфична для cnfiguration.

на самом базовом уровне, у меня есть класс конфигурации, в котором ничего нет - он пуст. У меня также есть метод Configure, который возвращает класс конфигурации и позволяет вам называть методы на нем:

# config.rb
class Configuration
end

class MySystem
  def self.configure
    @config ||= Configuration.new
    yield(@config) if block_given?
    @config
  end

  Dir.glob("plugins/**/*.rb").each{|f| require f}
end

MySystem.configure do |config|
  config.some_method
  config.some_value = "whatever"
  config.test = "that thing"
end

puts "some value is: #{MySystem.configure.some_value}"
puts "test #{MySystem.configure.test}"

чтобы получить some_method и some_value в классе конфигурации, у меня есть плагины, расширяющие объект конфигурации через модули:

# plugins/myconfig.rb
module MyConfiguration
  attr_accessor :some_value

  def some_method
    puts "do stuff, here"
  end
end

class Configuration
  include MyConfiguration
end

и

# plugins/another.rb
module AnotherConfiguration
  attr_accessor :test
end

class Configuration
  include AnotherConfiguration
end

чтобы загрузить плагины, вам нужен только один код для поиска файлов .rb в определенной папке и "потребовать" их. этот код может жить где угодно, пока он запускается сразу же после загрузки файла, который содержит его... Я бы, вероятно, поместил его в определение класса для MySystem или что-то в этом роде для начала. возможно, переместить его где-нибудь еще, когда имеет смысл.

Dir.glob("plugins/**/*.rb").each{|f| require f}

запустите config.rb, и вы получите вывод, который выглядит следующим образом:

do stuff, here 
some value is: whatever
test that thing

существует множество вариантов реализации различных частей этого, но это должно привести вас к следующему пути.

Ответ 2

Похоже, этот проект может помочь: https://github.com/eadz/plugman

Однако я не нашел ничего, что могло бы обрабатывать встроенные (gem) зависимости. Включение файлов Ruby является простым, но как только ваши плагины начинают требовать от других библиотек, эта простая модель разваливается (либо все депики должны быть установлены вместе с вашим приложением, либо вам нужен какой-то другой механизм, чтобы получить жемчужины зависимостей плагина в процессе).