Обработка метода с необязательным аргументом, за которым следует список ключевых аргументов - PullRequest
0 голосов
/ 10 января 2019

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

Вот что я получил:

def my_method(subject = nil, **options)
  [subject, options]
end

Выход метода соответствует ожидаемому в следующих случаях:

  • ничего

    my_method()
    # => [nil, {}]
    
  • предмет

    my_method('foo')
    # => ["foo", {}]
    
  • буквальный предмет с опциями

    my_method('foo', bar: 'bar')
    # => ["foo", {:bar=>"bar"}]
    
  • a Hash как предмет с параметрами

    my_method({foo: 'foo'}, bar: 'bar')
    # => [{:foo=>"foo"}, {:bar=>"bar"}]
    
  • без темы, только опции

    my_method(bar: 'bar')
    # => [nil, {:bar=>"bar"}]
    

При передаче Hash в качестве субъекта и без параметров желаемый результат:

my_method({foo: 'foo'})
# => [{:foo=>"foo"}, {}]

Но я получаю следующее; Я не понимаю правильный предмет:

my_method({foo: 'foo'})
# => [nil, {:foo=>"foo"}]

my_method(foo: 'foo') эквивалентно my_method({foo: 'foo'})? Любые идеи о том, как я могу получить желаемый результат?

Ответы [ 3 ]

0 голосов
/ 10 января 2019

Возможно, не самый лучший ответ, но вы можете попробовать с аргументом ключевого слова :

def my_method(subject: nil, **options)
  [ subject, options ]
end

Тогда

my_method(subject: {foo: 'foo'})

=> [{:foo=>"foo"}, {}]

Альтернатива:

Вы можете использовать

my_method({foo: 'foo'}, {})
0 голосов
/ 10 января 2019

Видите, у вас есть **options в качестве аргумента, который не имеет значения по умолчанию, а первый аргумент имеет значение по умолчанию. Итак, поймите следующее регистр с одним аргументом ,

Всякий раз, когда передается один аргумент, его пытаются присвоить второму аргументу (так как первый содержит значение по умолчанию nil), и если он терпит неудачу из-за несоответствия типов, он назначается первому аргументу. Вот так my_method(4) работает.

Теперь предположим, что у вас есть один аргумент, переданный в виде хэша, который соответствует присваиванию 2-му аргументу, затем, конечно, он присваивается второму аргументу, а first устанавливается по умолчанию nil.

Если вы хотите, чтобы это работало, то вы можете сделать следующее,

> my_method({sd: 4}, {})
 => [{:sd=>4}, {}]

Или вы можете указать имя аргумента при передаче,

> my_method(subject: {sd: 4})
 => [{:sd=>4}, {}]
0 голосов
/ 10 января 2019

Насколько я знаю, это ограничение того, как Ruby передает аргументы. Он не может отличить my_method({foo: 'foo'}) от my_method(foo: 'foo')

Почему бы не взломать это с этим?

if subject.is_a?(Hash) && options.empty?
  subject, options = nil, subject
end

Предполагается, что subject не должен быть хешем.

...