load
最近、Ruby クラスで 2 回呼び出すとバグが発生するという問題に遭遇しました(これは実際の例です)。これは、クラス本体でステートフル メソッド呼び出しが行われ、load
これらが 2 回実行されたためです。簡単な例は次のとおりです。
base.rb
:
class Base
def foo
puts "BASE"
end
end
derived.rb
:
require "./base"
class Derived < Base
alias_method :foo_aliased, :foo
def foo
puts "DERIVED!"
end
end
REPL からの実行:
$ load './derived.rb'
> true
$ Derived.new.foo
> DERIVED!
> nil
$ Derived.new.foo_aliased
> BASE
> nil
$ load './derived.rb'
> true
$ Derived.new.foo
> DERIVED!
> nil
$ Derived.new.foo_aliased
> DERIVED!
> nil
この例では、2 番目のload
原因alias_method
で元のエイリアスが破壊されます。その結果、元のメソッドへの完全なエイリアスを持つことに依存するすべてのコードが壊れました。
力ずくでクラスをリロードすることは十分に一般的であり (たとえば、each_run
Spork を使用した RSpec 構成の条項でよく見られます)、load
完全な使用を常に禁止するのは容易ではありません。そのため、バグを防ぐ唯一の方法は、クラス定義が「べき等」であることを確認することです。つまり、クラス定義から呼び出されることを意図したメソッドが、何回呼び出しても同じ結果を生成することを確認する必要があります。再ロードしてもコードが壊れないという事実は、暗黙の慣習を示唆しているようです。
これを義務付けるRubyクラス設計のスタイルガイドはありますか? もしそうなら、これらのセマンティクスを強制するための一般的なテクニックは何ですか? 一部のメソッドでは、同じメソッドが同じ引数で再実行されるのを防ぐためにメモ化を行うことができますが、他のようなものalias_method
は回避するのが難しいようです。