Выходят ли операторы Ruby 'require' изнутри или вне определения класса? - PullRequest
42 голосов
/ 03 марта 2009

При использовании файлов классов в Ruby вы помещаете операторы 'require' вверху файла или внутри определения класса?

Ответы [ 7 ]

51 голосов
/ 03 марта 2009

Технически это не имеет большого значения. require - это обычный вызов метода, и область, в которой он вызывается, не влияет на его работу. Единственное различие в размещении состоит в том, что оно будет выполнено, когда любой код, в который он помещен, будет оценен.

Практически, вы должны поставить их сверху, чтобы люди могли сразу увидеть зависимости файла. Это традиционное место для этого.

21 голосов
/ 03 марта 2009

вверху.

require 'rubygems'
require 'fastercsv'

class MyClass
  # Do stuff with FasterCSV
end
14 голосов
/ 03 марта 2009

Я вижу возможную причину не помещать require в начало файла: где это дорого для загрузки и не всегда выполняется. Один случай, который мне приходит в голову, это когда, например, код и его тесты находятся в одном файле, что я люблю время от времени делать, в частности, для кода небольшой библиотеки. Затем я могу запустить файл из моего редактора и запустить тесты. В этом случае, когда файл 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
10 голосов
/ 03 марта 2009

Не имеет значения, куда вы их поместили, но если вы поместите их в class или module выражение, то похоже, что вы импортируете все, что находится в require d файл в пространство имен класса, что не соответствует действительности: все заканчивается глобальным пространством имен (или какими-либо пространствами имен, определенными в библиотеке ).

Итак, лучше разместите их сверху, чтобы избежать путаницы.

4 голосов
/ 03 марта 2009

В верхней части файла большинство (но не все) языки обрабатывают импорт таким образом. Я нахожу это намного чище и легче обращаться с ними таким образом.

Я думаю, что это действительно имеет смысл только так ... как будто вы попали в файл в середине:

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'

как видите, их было бы очень сложно отследить. Не говоря уже о том, что если вы хотите использовать импортированные функции ранее в своем коде , вам, вероятно, придется вернуться назад и включить его снова, поскольку другой импорт будет специфичным для этого класса. Импорт одних и тех же файлов также может привести к значительным издержкам во время выполнения.

1 голос
/ 14 апреля 2016

Я чувствую, что оператор require принадлежит классу. Использование классов означает, что мы принимаем базовый принцип ООП, а именно объекты должны быть как можно слабее связаны. Для меня это означает минимизацию внешних зависимостей. Если позже я переместу класс в его собственный файл, я не хочу, чтобы он прерывался, потому что я не отслеживал все необходимые require утверждения, которые потребляет класс.

Это не вызывает проблем с дублированием require операторов в файле, и это упрощает рефакторинг, который неизбежно произойдет следующим программистом, наследующим ваш код.

0 голосов
/ 19 февраля 2019

В большинстве ответов рекомендуется ставить оператор 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 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...