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.load_plugins_method のように、すべてをカプセル化するクラス メソッドを TemplateMethods で構築することをお勧めします。ここでの強打は、動的モジュールのインクルージョンによって実行される侵入アクションについて警告します。

それは仕事をするはずです:)

于 2012-10-01T14:36:27.773 に答える