Rubyの「require」ステートメントはクラス定義の内部または外部にありますか?
質問
Rubyでクラスファイルを使用する場合、「requires」ステートメントをファイルの上部に配置しますか、それともクラス定義内に配置しますか?
解決
技術的には、実際には問題ではありません。 require
は通常のメソッド呼び出しであり、呼び出される範囲はその動作に影響しません。配置の唯一の違いは、配置されたコードが評価されたときに実行されることです。
実際には、ファイルの依存関係がひと目でわかるように、最上位に配置する必要があります。それが伝統的な場所です。
他のヒント
上部。
require 'rubygems'
require 'fastercsv'
class MyClass
# Do stuff with FasterCSV
end
ファイルの先頭に require
を配置しない理由として考えられるのは、読み込みに時間がかかり、常に実行されるわけではないことです。私の場合、たとえばコードとそのテストが同じファイルに含まれている場合があります。これは、特に小さなライブラリコードの場合に時々行いたいことです。その後、エディターからファイルを実行し、テストを実行できます。この場合、ファイルが他の場所から require
dされたとき、 test / unit
をロードしたくありません。
次のようなもの:
def some_useful_library_function()
return 1
end
if __FILE__ == <*>
require 'test/unit'
class TestUsefulThing < Test::Unit::TestCase
def test_it_returns_1
assert_equal 1, some_useful_library_function()
end
end
end
実際に配置する場所は重要ではありませんが、 class
または module
式の内部に配置すると、あなたが require
dファイルにあるものをクラスの名前空間にインポートするように、それは真実ではありません:すべてがグローバルな名前空間(またはライブラリで >)。
そのため、混乱を避けるために、それらを一番上に置いてください。
ファイルの先頭では、大部分の(すべてではない)言語がこの方法でインポートを処理します。この方法で処理する方がずっときれいで簡単だと思います。
この方法は本当に理にかなっていると思います...ファイルの途中で取得するように:
class Foo
def initialize(init_value)
@instance_var = init_value
# some 500 lines of code later....
end
end
class Bar
# oh look i need an import now!
require 'breakpoint'
ご覧のとおり、それらを追跡するのは非常に困難です。インポートされた関数をコードの以前で使用したい場合は言うまでもありませんが、他のインポートはそのクラスに固有であるため、バックトラックして再度含める必要があります。同じファイルをインポートすると、実行時にも多くのオーバーヘッドが発生します。
require ステートメントはクラス内に属していると思います。クラスを使用するということは、OOPの基本原則を受け入れることを意味します。つまり、オブジェクトはできるだけ疎結合でなければなりません。それは外部の依存関係を最小限に抑えることを意味します。後でクラスを独自のファイルに移動する場合、クラスが消費するすべての必要な require ステートメントを追跡しなかったため、クラスを中断させたくありません。
ファイル内で重複する require ステートメントが発生しても問題は発生せず、コードを継承する次のプログラマーによって必然的に発生するリファクタリングが簡素化されます。
ほとんどの回答では、ファイルの先頭に require ステートメントを置くことをお勧めします。ただし、ネストされたクラス/モジュールが必要な場合は、代わりにクラスの最上部に配置することを検討してください。この例を見てください:
# foo.rb
require './foo/bar'
class Foo < Struct.new(:name, :description)
def bar
Bar.new(self)
end
end
# foo/bar.rb
class Foo
class Bar < Struct.new(:foo)
end
end
irb:
require './foo'
# ...
# TypeError (superclass mismatch for class Foo)
これは、 Bar が Foo 内にネストされており、 Bar クラスを内にネストして、 Foo クラス。ただし、 Foo はまだ定義されていないため、ネスト構造で定義されています。 Bar が正常に必要になったら、別のクラスを継承する Foo クラスを定義しようとします。これは Foo が既に(ネストされた構造によって)定義されており、継承はクラスの初期定義でのみ発生するため、失敗します。したがって、レイズ:
TypeError(クラスFooのスーパークラスの不一致)
この問題は、requireステートメントを Foo クラス内に移動するだけで解決できます。