Rubyでクラスファイルを使用する場合、「requires」ステートメントをファイルの先頭に配置しますか、それともクラス定義内に配置しますか?
技術的には、それは実際には問題ではありません。 require
は単なる通常のメソッド呼び出しであり、呼び出されるスコープはその動作に影響しません。配置による唯一の違いは、配置されたコードが評価されたときに実行されることです。
実際には、ファイルの依存関係が一目でわかるように、それらを一番上に配置する必要があります。それはそれのための伝統的な場所です。
頂点で。
require 'rubygems'
require 'fastercsv'
class MyClass
# Do stuff with FasterCSV
end
ファイルの先頭にrequire
を配置しない理由として考えられるものがあります。ロードにコストがかかり、常に実行されるとは限りません。私が思い浮かぶケースの1つは、たとえば、コードとそのテストが同じファイル内にある場合です。これは、特に小さなライブラリコードに対して時々行うのが好きなことです。次に、エディターからファイルを実行して、テストを実行します。この場合、ファイルが他の場所からrequire
dである場合、test/unit
をロードしたくありません。
このようなもの:
def some_useful_library_function()
return 1
end
if __FILE__ == $0
require 'test/unit'
class TestUsefulThing < Test::Unit::TestCase
def test_it_returns_1
assert_equal 1, some_useful_library_function()
end
end
end
それらをどこに置くかは実際には重要ではありませんが、それらを置くとinsideclass
または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クラス内に移動するだけで解決できます。