Поскольку в ruby нет типа, как программисты Ruby уверены, что функция получает правильные аргументы? Прямо сейчас, я повторяю инструкции if object.kind_of
/instance_of
для проверки и повышения ошибок во время выполнения, что является уродливым. Должен быть лучший способ сделать это.
Как программисты Ruby выполняют проверку типов?
Ответ 1
Ruby, конечно, динамически типизирован.
Таким образом, документация метода определяет контракт типа; информация о типе перемещается из формальной системы типов в документацию по [неофициальному типу спецификации]. Я смешиваю такие общие понятия, как "действует как массив", и такие особенности, как "строка". Вызывающий должен работать только с указанными типами.
Если вызывающий абонент нарушает этот контракт, все может произойти. Метод не должен беспокоиться: он использовался неправильно.
В свете вышеизложенного я избегаю проверки определенного типа и не пытаюсь создать перегрузки с таким поведением.
Модульные тесты могут помочь гарантировать, что контракт работает для ожидаемых данных.
Ответ 2
Мой личный подход, который я не уверен, является ли это рекомендуемым способом в целом, - это проверять тип и выполнять другие проверки после возникновения ошибки. Я поместил процедуру проверки типа в блок спасения. Таким образом, я могу избежать потери производительности, когда приводятся правильные аргументы, но все равно вернет правильное сообщение об ошибке при возникновении ошибки.
def foo arg1, arg2, arg3
...
main_routine
...
rescue
## check for type and other validations
raise "Expecting an array: #{arg1.inspect}" unless arg1.kind_of?(Array)
raise "The first argument must be of length 2: #{arg1.inspect}" unless arg1.length == 2
raise "Expecting a string: #{arg2.inspect}" unless arg2.kind_of?(String)
raise "The second argument must not be empty" if arg2.empty?
...
raise "This is `foo' bug. Something unexpected happened: #{$!.message}"
end
Предположим, что в main_routine
вы используете метод each
на arg1
, предполагая, что arg1
является массивом. Если окажется, что это что-то еще, для которого each
не определено, то сообщение об ошибке будет выглядеть как method each not defined on ...
, которое с точки зрения пользователя метода foo
может быть не полезно. В этом случае исходное сообщение об ошибке будет заменено сообщением Expecting an array: ...
, что гораздо более полезно.
Ответ 3
Если у метода есть причина для существования, он будет вызываться.
Если будут написаны разумные тесты, все будет вызвано.
И если вызывается каждый метод, то каждый метод будет проверяться по типу.
Не тратьте время на ввод проверок типов, которые могут излишне ограничивать абонентов и в любом случае будут дублировать проверку времени выполнения. Вместо этого проводите тесты времени.
Ответ 4
Я рекомендую использовать рейз в начале метода, чтобы добавить ручную проверку типа, простую и эффективную:
def foo(bar)
raise TypeError, "You called foo without the bar:String needed" unless bar.is_a? String
bar.upcase
end
Лучший способ, когда у вас нет большого количества параметров, также рекомендуется использовать аргументы ключевых слов, доступные на ruby 2+, если у вас есть несколько параметров и следить за его текущими/будущими сведениями о реализации, они улучшают ситуацию, программист - это способ узнать, равно ли значение nil.
плюс: вы можете использовать настраиваемое исключение
class NotStringError < TypeError
def message
"be creative, use metaprogramming ;)"
#...
raise NotStringError
Ответ 5
Вы можете использовать "Дизайн по контракту" с contracts рубиновый камень. Мне очень приятно.