Ruby插件架构

11 ruby plugins metaprogramming

我想要一个基本的小程序示例,它读入两个插件并注册它们.这两个插件以无冲突的方式以相同的方式挂接到基本程序中.

我对任何编程语言的元编程都很陌生,我不知道从哪里开始.

Der*_*ley 9

我一直在研究这个问题.我已经尝试了很多不同的方法来做这件事并向很多人寻求建议.我仍然不确定我所拥有的是"正确的方式",但它运作良好而且很容易做到.

在我的情况下,我特别关注配置并引入配置插件,但即使我的术语特定于配置,原理也是一样的.

在一个非常基本的层面上,我有一个没有任何内容的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}"
Run Code Online (Sandbox Code Playgroud)

为了获得配置类上的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
Run Code Online (Sandbox Code Playgroud)

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

class Configuration
  include AnotherConfiguration
end
Run Code Online (Sandbox Code Playgroud)

要加载插件,您只需要一个代码来查找特定文件夹中的.rb文件并"需要"它们.只要在包含它的文件被加载时它立即运行,这个代码可以存在任何地方...我可能会把它放在MySystem的类定义中或类似的东西开始.当有意义时,可能会把它移到其他地方.

Dir.glob("plugins/**/*.rb").each{|f| require f}
Run Code Online (Sandbox Code Playgroud)

运行config.rb,你会得到如下所示的输出:

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

有很多选项来实现这个的各个部分,但这应该让你走上正轨.