0

我有一个类,我希望其他开发人员能够创建模块来扩展我的类并给它更多instance variables

如何根据特定文件夹中的文件自动在我的类中包含模块?即加载所有文件并将它们作为我的课程的模块包含在内

我怎样才能做到这一点并以某种方式避免方法命名冲突?我在想我可以在初始化方法中传递插件的名称,然后这样做:

class MyClass
  def initialize(plugin_name=nil)
  end

  def method_missing(method_name)
    "#{plugin_name}".send(method_name)
  end
end

理论上这样的工作是否可行,请在method_missing中提供帮助,因为我以前从未写过。我试图基本上指定一个特定的插件名称以避免任何名称冲突。

或者我应该在包含插件时在方法冲突时输出错误吗?

4

1 回答 1

2

让外部代码在你的类中融合听起来很危险,并且正如你所猜测的那样会导致名称冲突。它还可能导致意外行为,因为您允许外部代码与您的类内部发生混乱。

处理插件的最佳方法是封装将被替换的行为。让我们举个例子:

假设您正在构建一个 Logger,我们可以想象您可以创建插件来指定将写入日志的位置。

然后,您可以创建以下类:

class Logger 
   def initialize(store)
     @store = store 
   end

   def info(message)
     @store.write(:info, message) 
   end 
 end 

class StandardOutputStore
  def write(level, message) 
    puts "#{level}: #{message}" 
  end 
end 

class FileStore
  def initalize(filename)
    @filename = filename
  end

  def write(level, message)
    File.open(@filename, "a") do |file|
      file.write("#{level}: #{message}") 
    end
  end
end

然后你可以通过这种方式实例化正确的插件:

logger = Logger.new(StandardOutputStore.new)
logger.warn "hello"

logger = Logger.new(FileStore.new("/tmp/log"))
logger.warn "hello" 

这种做事方式提供了模块化、更大的灵活性,并且比使用外部代码重载类中的内容更可靠。

加载在目录中找到的模块是玩弄 Dir.glob 和 require 的问题。要探索在您的插件目录下找到的内容,您可以强制您的用户在模块中编写插件,例如 Foo::Plugins::FileStore 并在需要文件后检查 Foo::Plugins 模块中存在哪些常量。有关详细信息,请参阅http://www.ruby-doc.org/core-1.9.3/Module.html#method-i-constants

编辑:由于您向 ERB 模板提供了方法,因此您没有任何要映射的接口,因此您可以执行以下操作:

插件采用以下形式:

module Plugins
  module Emoticons
    def smile
        ":-)"
    end
  end
end

然后,您可以使用以下内容加载它们:

Dir["/plugins/*.rb"].each {|file| require file }

并包含它们,因为 TemplateMethods 是一个包含在您的 ERB 模板上下文中的模块。

 Plugins.constants.each do |constant|
   mod = Plugins.const_get constant
   TemplateMethods.send(:include, mod)
 end

使用 send 不是很优雅,我建议在 TemplateMethods 上构建一个封装整个事物的类方法,例如 TemplateMethods.load_plugins_method!这里的爆炸会警告动态模块包含所做的侵入性操作。

那应该做的工作:)

于 2012-10-01T14:36:27.773 回答