ささだです。

 あるファイルを require 中に、たとえばその先で require する
ものがインストールされていなかった場合など、例外が発生します。
そのとき、$" には、最初に require したファイルが記録されます
ので、次に require しても、読み込みを行いません。たとえば、
例外発生要因を取り除いた後にもう一度 require するような場合、
これに気づかずにはまるかもしれません(というか、はまった)。

 このような可能性がある場合の対処について、定石などあれば教
えてください。


 例をもうちょっと具体的に書きます。

・N というアプリケーションがありました

・N はプラグイン機能を有しています

・N はサーバアプリケーションで、基本的にずーっと動いています
  (終了させたくありません)

・N は P というプラグインをロードしようとしました

・P は ライブラリ L1 を require するのですが、L1 は L2 を必要としました
  生憎その環境には L2 がインストールされていませんでした

・require L2 で例外が発生しますが、N はその例外をフックし、
  P のロード失敗と、その原因をユーザに知らせ、動き続けました

・そこで、ユーザは L2 をインストールしてから、再度 P をロード
  しようとしますが、P が L1 を require しようとしたところ、
  すでに L1 が $" に入っていたため、L1 がきちんと require できませんでした
  なので、P の実行は失敗してしまいました(不完全な L1 を利用
  するため)


 通常(?)のアプリケーションの場合、require L2 の段階で例
外が発生し、アプリケーション自体が終了するためこのような問題
はあまり気にならないと思うのですが、サーバ系アプリケーション
などでは問題になるかと思います。


 さて、この例では、アプリケーション N はどんな対策を取れば
いいんでしょうか。何か定石でもありましたらご教示ください。


・考えてみた解決案1

 プラグイン(P)中で require する場合、特別な関数
require_in_plugin(libname) を用意する。この関数では、require
に失敗すると、その libname を $" から取ってしまう。

	def require_in_plugin libname
	  begin
	    require libname
	  rescue Exception
	    $".delete libname
	    raise
	  end
	end


この解決案の問題点:

 L1 中で例外が発生した場合、なんとなくそれでいいような気が
するのだけれど、たとえば L1 が L2、L2 が L3, ... LN-1 が LN
を require していたとき、LN 中で例外が発生した場合、L1 のみ
が $" から除かれ、再度 L1 を require しても、L2 は require
されず、問題の LN は require されない。


・考えてみた解決案2

 ということで、require_in_plugin は $" を保存し、require を
行う。もし require 中で例外が発生した場合、$".replace(old_libs)
のように、取り替えちゃう。

	def require_in_plugin libname
	  begin
	    old_libs = $"
	    require libname
	  rescue Exception
	    $".replace old_libs
	    raise
	  end
	end

(マルチスレッドによる並行実行はあんまり考えたくない)


・考えてみた解決案3

 そんなケースはレアなので、あきらめる。



 なにか、スマートな方法があれば教えてください。

-- 
// SASADA Koichi at atdot dot net
//


N:  nadoka
P:  rss_check.nb
L1: rss_check.rb
L2: zlib


 別に困らないんで、Kernel.require を上記関数で書き換えてしま
うってのもいいのかなぁ