おそらくリセット時の動作が[ 例外派生→スクリプトの再読み込み ] となっている為だと思います。組み込み系はそのまま、スクリプトだけが読み込まれるので 組み込み系に対しては2度目のaliasが実行されてしまい無限ループになってしまっているようです。
例)# Script1 class Kumikomi def initialize p "元の処理" end endScript1に処理を追加する場合次のようにaliasを使う方法がよくとられます。
# Script2 class Kumikomi alias :_tuika_initialize :initialize def initialize _tuika_initialize p "追加処理" end endこれは
class Kumikomi def _tuika_initialize p "元の処理" end def initialize _tuika_initialize p "追加処理" end endと書くのとほぼ同じ処理になるのですが、Script2を再度実行してしまうと以下のようになってしまいます
class Kumikomi def _tuika_initialize _tuika_initialize p "追加処理" end def initialize _tuika_initialize p "追加処理" end end
「_tuika_initialize」内で自身を呼び出すようになり無限ループになってしまっています。 無限ループ→「stack too deep」となるわけです。
スクリプトの最後(mainの直前)にグローバル変数を設定しそれで判別
# Script2_Fixed2 class Kumikomi unless $teikitou_script_loaded alias :_tuika_initialize :initialize def initialize _tuika_initialize p "追加処理" end end end # 後ろの方 $teikitou_script_loaded = true
リセットしてもグローバル変数はそのままなので一度最後まで読まれたかどうかの判断に使えます。
スクリプト素材等では素材の最後にグローバル変数を定義したりする事になると思いますが、 その場合はまず他と重ならないようなユニークな名前にする必要があります。
# Script2_Fixed2 class Kumikomi unless $@ alias :_tuika_initialize :initialize def initialize _tuika_initialize p "追加処理" end end end
"$@"に値が入っていたらリセット後なので二度目の"alias"を実行しないようにしています。
リセット以外で例外情報が入っていたら?とかどこかで"$@"がクリアされていたら?とかが気になるので 個人的には好きな方法ではありません。実際そんな状況はまずないと思いますが。
# Script2_Fixed3 class Kumikomi unless private_method_defined?(:_tuika_initialize) alias :_tuika_initialize :initialize def initialize _tuika_initialize p "追加処理" end end end
aliasをによって定義される「_tuika_initialize」が定義されているかどうかで判別しています。
元のメソッドがpublicメソッドなら"method_defined?", privateメソッドなら"private_method_defined?" 使えばたぶんOKです。
"initialize"メソッドは何も指定していなくても自動でprivateになります
これらの対処法は対策が必要ではないaliasの部分に対して行ってもデメリットはありません。 むしろ無駄に2回目のaliasを実行しなくていいのでかすかにメリットがあるくらい。 とりあえずaliasを使う時には書いておく位でもいいと思います。
組み込み系以外でもスーパークラスから継承されたメソッドをオーバーライドせずにそのままaliasしている 場合はちゃんと対策する必要があります。
# Script4 (faled case) class Parent def test p "Parent" end end class Child < Parent alias :_tuika_test :test def test _tuika_test p "Child" end end
上の例では
def test _tuika_test p "Child" end
の部分でオーバーライドされているので、リセット後の
alias :_tuika_test :test
では"Parent"クラスの"test"メソッドではなく"Child"クラスで新たに定義された "test"メソッドが利用される事になります。 結果的に組み込み系への"alias"と同じような状況になります。
この場合も上記の対処法で対処できます。
リセット時にグローバル変数等はリセットされません。またrequireも読み込み情報がそのままなので 読み込まれません。※1 リセット後も読み込みたい場合はload等を使った方がいいかもしれません。※2