クラス内で外部コードを溶かすことを許可するのは危険に思え、ご想像のとおり、名前の競合が発生します。また、外部コードがクラスの内部を混乱させることを許可しているため、予期しない動作が発生する可能性もあります。
プラグインを処理する最善の方法は、置き換えられる動作をカプセル化することです。例を見てみましょう:
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 で構築することをお勧めします。ここでの強打は、動的モジュールのインクルージョンによって実行される侵入アクションについて警告します。
それは仕事をするはずです:)