web-dev-qa-db-ja.com

Ruby 'require'ステートメントはクラス定義の内部または外部にありますか?

Rubyでクラスファイルを使用する場合、「requires」ステートメントをファイルの先頭に配置しますか、それともクラス定義内に配置しますか?

45
Ash

技術的には、それは実際には問題ではありません。 requireは単なる通常のメソッド呼び出しであり、呼び出されるスコープはその動作に影響しません。配置による唯一の違いは、配置されたコードが評価されたときに実行されることです。

実際には、ファイルの依存関係が一目でわかるように、それらを一番上に配置する必要があります。それはそれのための伝統的な場所です。

56
Chuck

頂点で。

require 'rubygems'
require 'fastercsv'

class MyClass
  # Do stuff with FasterCSV
end
22
ewakened

ファイルの先頭にrequireを配置しない理由として考えられるものがあります。ロードにコストがかかり、常に実行されるとは限りません。私が思い浮かぶケースの1つは、たとえば、コードとそのテストが同じファイル内にある場合です。これは、特に小さなライブラリコードに対して時々行うのが好きなことです。次に、エディターからファイルを実行して、テストを実行します。この場合、ファイルが他の場所からrequiredである場合、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
14
Mike Woodhouse

それらをどこに置くかは実際には重要ではありませんが、それらを置くとinsideclassまたはmodule式の場合、何でもインポートしているように見えますrequiredファイルをクラスの名前空間に挿入しますが、これは正しくありません。すべてがグローバル名前空間(または定義されている名前空間ライブラリ内)になります。

したがって、混乱を避けるために、それらを一番上に配置することをお勧めします。

10
Jörg W Mittag

ファイルの先頭では、大部分(すべてではない)の言語がこの方法でインポートを処理します。この方法でそれらを処理する方がはるかにクリーンで簡単だと思います。

私はそれが本当にこの方法でのみ意味があると思います...あなたがファイルの途中に入るように:

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'

ご覧のとおり、それらを追跡するのは非常に困難です。インポートされた関数を使用したい場合は言うまでもありませんコードの前半、他のインポートはそのクラスに固有であるため、おそらくバックトラックして再度含める必要があります。同じファイルをインポートすると、実行時にも多くのオーバーヘッドが発生します。

4
John T

requireステートメントはクラス内に属しているように感じます。クラスを使用するということは、OOPの基本的な信条を受け入れることを意味します。つまり、オブジェクトは可能な限り疎結合にする必要があります。私にとって、それは外部の依存関係を最小限に抑えることを意味します。後でクラスを独自のファイルに移動する場合、クラスが消費する必要なすべてのrequireステートメントを追跡しなかったため、クラスを壊したくありません。

ファイル内に重複するrequireステートメントがあっても問題は発生せず、コードを継承する次のプログラマーによって必然的に行われるリファクタリングが簡素化されます。

1
WiiBopp

ほとんどの回答では、ファイルの先頭に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)

これは、BarFoo内にネストされており、定義する必要があるために発生しますそのため、BarクラスをFooクラス内にネストします。ただし、Fooはまだ定義されていないため、ネストされた構造によって定義されています。 Barが正常に要求された後、Fooクラスを定義しようとします。別のクラスから継承します。 Fooは(ネストされた構造によって)すでに定義されており、継承はクラスの初期定義でのみ発生する可能性があるため、これは失敗します。したがって、上げる:

TypeError(クラスFooのスーパークラスの不一致)

この問題は、requireステートメントをFooクラス内に移動するだけで解決できます。

0
3limin4t0r