Ruby插件架构

12

我需要一个非常基本的例子来展示一个小型基础程序,它可以读取两个插件并将它们注册到程序中。这两个插件以相同的方式与基础程序进行钩子绑定,且不会产生冲突。

我对任何编程语言中的元编程都非常陌生,不确定从何处开始。


1
抱歉有些迂腐,但插件不是与Rails框架相关联的吗,而不是与Ruby本身相关联的吗? - Andrew Grimm
Rails框架有插件,但我说的是在Ruby应用程序的上下文中创建插件系统。假设你有一个读取文本文件的类。我想创建一个插件系统,让你编写一个插件类,将其钩入到读取器类中,这样你就可以创建一个UpCase插件或1337插件来修改输出。这只是一个基本的例子,但应该能给你一个想法。 - user286355
7
Ruby不仅仅是Rails,尽管Rails是最著名的框架。说插件与Rails相关就像说汽油与跑车相关一样。实际上还有许多其他东西也使用汽油,包括非机动车辆。 - Derick Bailey
@Derick:我问这个问题实际上是因为我不使用Rails(只用纯粹的Ruby对象),并且没有遇到过插件。 - Andrew Grimm
2个回答

10
我已经在解决这个问题一段时间了。我尝试了许多不同的方法,并向很多人寻求建议。我仍然不确定我所做的是否是“正确的方式”,但它运行良好且易于操作。
在我的情况下,我特别关注配置和引入配置插件,即使术语对我的配置是具体的,但原理是相同的。
非常基础的,我有一个空的Configuration类。我还有一个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文件并使用'require'命令加载它们。这个代码可以放在任何地方,只要在包含它的文件被加载时立即运行即可... 我可能会先将其放在MySystem类定义中之类的地方。后面如果有必要,再将其移动到其他地方。

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

运行config.rb,你会得到类似以下内容的输出:

这里做一些事情
某个值是:任何东西
测试那个东西

有很多方法可以实现其中的各个部分,但这应该能让你走上正确的方向。


2

看起来这个项目可能会有所帮助:https://github.com/eadz/plugman

然而,我还没有找到任何可以处理嵌入式(gem)依赖关系的东西。包括Ruby文件很简单,但是一旦你的插件开始需要其他库,那么这个简单模型就会崩溃(要么所有依赖项都必须与应用程序一起安装,要么您需要某种机制将插件依赖的gem引入进程中)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接