Идут ли инструкции Ruby 'require' внутрь или за пределы определения класса?
Вопрос
При использовании файлов классов в Ruby вы помещаете инструкции 'requireds' в начало файла или внутри определения класса?
Решение
Технически, это действительно не имеет значения. require
это просто обычный вызов метода, и область, в которой он вызывается, не влияет на то, как он работает.Единственное отличие размещения заключается в том, что оно будет выполнено, когда будет вычислен любой код, в который оно помещено.
С практической точки зрения, вы должны поместить их сверху, чтобы люди могли сразу увидеть зависимости файла.Это традиционное место для этого.
Другие советы
на самом верху.
require 'rubygems'
require 'fastercsv'
class MyClass
# Do stuff with FasterCSV
end
Я вижу возможную причину для того, чтобы не ставить require
в верхней части файла:где загрузка обходится дорого и не всегда выполняется.Один случай, который приходит мне на ум, - это когда, например, код и его тесты находятся в одном файле, что я люблю делать время от времени, в частности, для кода небольшой библиотеки.Затем я могу запустить файл из своего редактора, и тесты будут запущены.В этом случае, когда файл находится require
буду приходить откуда-то еще, я не хочу 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
На самом деле не имеет значения, куда вы их положите, но если вы их положите внутри a class
или module
выражение, тогда это выглядит так, как будто вы импортируете все, что есть в require
общий файл в пространство имен класса, что неверно:все заканчивается в глобальном пространстве имен (или любых других определенных пространствах имен в библиотеке).
Поэтому лучше разместите их вверху, чтобы избежать какой-либо путаницы.
В верхней части файла большинство (но не все) языков обрабатывают импорт таким образом.Я нахожу, что таким образом с ними гораздо чище и проще обращаться.
Я думаю, что на самом деле это имеет смысл только так...как будто ты добираешься до середины файла, тогда:
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'
как вы можете видеть, отследить их было бы очень трудно.Не говоря уже о том, хотели ли вы использовать импортированные функции ранее в вашем коде, вам, вероятно, придется вернуться назад и включить его снова, потому что другой импорт будет специфичен для этого класса.Импорт одних и тех же файлов также привел бы к большим накладным расходам во время выполнения.
Я чувствую, что требовать оператор принадлежит классу.Использование классов означает, что мы принимаем базовый принцип ООП, а именно: объекты должны быть как можно более слабо связаны.Для меня это подразумевает минимизацию внешних зависимостей.Если я позже перемещу класс в его собственный файл, я не хочу, чтобы он прерывался, потому что я не отследил все необходимые требовать операторы, которые использует класс.
Наличие дубликатов не вызывает никаких проблем требовать инструкции в файле, и это упрощает рефакторинг, который неизбежно будет выполнен следующим программистом, наследующим ваш код.
В большинстве ответов рекомендуется ставить требовать инструкции в верхней части файла.Однако, когда требуются вложенные классы / модули, вы можете рассмотреть возможность размещения их вместо этого в классе (вверху).Взгляните на этот пример:
# 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)
Это происходит потому, что Бар вложен внутрь Фу и его нужно будет определить как таковой путем вложения Бар класс внутри Фу класс.Однако с тех пор , как Фу еще не определено, сейчас оно определяется вложенной структурой.После Бар успешно требуется, теперь мы попытаемся определить Фу класс, который наследуется от другого класса.Это не удается из-за того, что Фу уже определен (вложенной структурой), и наследование может происходить только при начальном определении класса.Таким образом, повышая:
TypeError (несоответствие суперкласса классу Foo)
Эта проблема может быть решена простым перемещением инструкции require внутри Фу класс.