Параметры и аргументы ключевых слов являются относительно новыми в Ruby.Они были введены только в Ruby 2.0.
До того, как у Ruby были параметры и аргументы ключевых слов, широко использовалась идиома передачи литерала Hash
в качестве последнего аргумента метода.Эта идиома выглядела примерно так:
DEFAULTS = {
:mode => 'w',
:eol => :crlf,
}
def open_file(name, options = {})
raise ArgumentError unless options[:encoding]
options = DEFAULTS.merge(option)
mode, eol, encoding = options[:mode], options[:eol], options[:encoding]
# do your thing
end
open_file('test.txt', { :mode => 'r', :encoding => 'UTF-8' })
Для того, чтобы она выглядела немного более похожей на ключевое слово, вам разрешается опускать скобки, если вы передаете литерал Hash
как оченьпоследний аргумент отправки сообщения:
open_file('test.txt', :mode => 'r', :encoding => 'UTF-8')
В Ruby 1.9 был введен альтернативный синтаксис для ограниченного подмножества литералов Hash
: когда ключом является Symbol
, который также является допустимым идентификатором Ruby(например, :foo
, но не :'foo-bar'
), тогда вы можете написать это так:
{ foo: bar }
вместо
{ :foo => bar }
Итак, мы могли бы вызвать наш метод сверхукак это:
open_file('test.txt', { mode: 'r', encoding: 'UTF-8' })
и, поскольку правило об исключении скобок все еще применяется, также вот так:
open_file('test.txt', mode: 'r', encoding: 'UTF-8')
Это очень похоже на аргументы ключевых слов в других языках.Фактически, этот альтернативный буквальный синтаксис для Hash
es с ключами Symbol
был по крайней мере частично специально разработан для обеспечения пути перехода для введения параметров и аргументов ключевых слов в Ruby.
В Ruby 2.0 необязательные параметры ключевого словас ключевыми словами по умолчанию были введены аргументы:
def open_file(name, mode: 'w', eol: :crlf, encoding: nil)
raise ArgumentError unless encoding
# do your thing
end
Затем в Ruby 2.1 обязательные параметры и аргументы ключевых слов:
def open_file(name, mode: 'w', eol: :crlf, encoding:)
# do your thing
end
Как вы, вероятно, знаете, вызов этого метода выглядит точно так же, как и раньше:
open_file('test.txt', mode: 'r', encoding: 'UTF-8')
Обратите внимание, что вы больше не можете сказать, что это значит!Вы не можете знать, является ли mode: 'r', encoding: 'UTF-8'
литералом Hash
или двумя ключевыми аргументами (другими словами, вы даже не знаете, является ли это одним или двумя аргументами!), Не глядя на определение метода, который вы вызываете.
Было решено, что Ruby 2.0 должен быть максимально обратно и вперед совместим с Ruby 1.9.
Следовательно, все следующее должно быть верным:
- Метод, которыйопределяется с помощью хэша опций и вызывается с хэшем опций, он все еще должен работать.
- Метод, который определяется с помощью хэша опций и вызывается с аргументами ключевого слова, должен работать.
- Методэто определяется параметрами ключевого слова и вызывается с помощью хеш-литерала параметров, который все еще должен работать.
Чтобы все это работало, существует много неявных преобразований между литералами хеш-функции и аргументами ключевого слова.Чтобы заставить это работать без неприятных угловых случаев, просто намного проще, если параметры ключевого слова и аргументы ключевого слова допускаются только там, где ранее был разрешен синтаксис "поддельного" ключевого слова, то есть в самом конце списка параметров исписок аргументов.
На самом деле, есть все еще много неприятных угловых случаев, вызванных этим "размыванием линий" между хешами и параметрами ключевых слов.Если вы посмотрите средство отслеживания проблем Ruby, то обнаружите, что значительная часть проблем, о которых сообщалось в Ruby 2.0, связана с неинтуитивным или просто ошибочным поведением в этом отношении.Каждый новый выпуск приносит новые изменения, но создается впечатление, что для каждой дыры, которую они исправляют, они создают две новые.
Теперь, просто представьте, как это было бы, если бы правила были еще менее строгими!
Вот несколько примеров упомянутых выше проблем: