Я хочу передать необязательный аргумент (любой тип данных, даже хэш), за которым следует список аргументов ключевого слова (который может быть пустым) в метод.
Вот что у меня получилось:
def my_method(subject = nil, **options)
[subject, options]
end
Результат метода ожидаемый в следующих случаях:
ничего такого
my_method()
# => [nil, {}]
предмет
my_method('foo')
# => ["foo", {}]
буквальный предмет с вариантами
my_method('foo', bar: 'bar')
# => ["foo", {:bar=>"bar"}]
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'})? Есть идеи, как я могу получить желаемый результат?

Насколько мне известно, это ограничение того, как Ruby передает аргументы. Он не может отличить my_method({foo: 'foo'}) от my_method(foo: 'foo').
Почему бы не обойти это с этим?
if subject.is_a?(Hash) && options.empty?
subject, options = nil, subject
end
Это предполагает, что subject не должен быть хешем.
Спасибо за Ваш ответ. К сожалению, иногда мне нужно передать хеш на subject.
@Taschetto Хорошо ... но как бы вы отличили тему nil и только варианты от темы Hash и без параметров?
my_method({foo: 'foo'}) должен быть предметом хеширования и без опций; my_method(foo: 'foo') должен быть нулевой темой и просто опциями. Но может я ошибаюсь.
@Taschetto Я почти уверен, что это ограничение Ruby. Он не может провести различие между этими двумя случаями. В таком случае я бы просто сделал subject необязательным.
Возможно, это не лучший ответ, но вы можете попробовать с аргумент ключевого слова:
def my_method(subject: nil, **options)
[ subject, options ]
end
потом
my_method(subject: {foo: 'foo'})
=> [{:foo=>"foo"}, {}]
Ты можешь использовать
my_method({foo: 'foo'}, {})
Спасибо за ответ. Да, это работает. Но в моем случае мне пришлось бы реорганизовать большое количество вызовов методов. Мне нужно поддерживать интерфейс метода.
@Taschetto, тогда my_method ({foo: 'foo'}, {}) может быть решением?
Видите ли, у вас есть **options в качестве аргумента, который не имеет значения по умолчанию, а первый аргумент имеет значение по умолчанию. Так что поймите следующее случай с одним аргументом,
Всякий раз, когда передается один аргумент, его пытаются назначить второму аргументу (поскольку первый по умолчанию имеет значение nil), и если он терпит неудачу из-за несоответствия типов, он назначается первому аргументу. Так работает my_method(4).
Теперь предположим, что у вас есть один аргумент, переданный как хэш, который соответствует назначению 2-му аргументу, тогда, конечно, он будет назначен второму аргументу, а для первого по умолчанию установлено значение nil.
Если вы хотите, чтобы это работало, вы можете сделать следующее:
> my_method({sd: 4}, {})
=> [{:sd=>4}, {}]
Или вы можете указать имя аргумента при передаче,
> my_method(subject: {sd: 4})
=> [{:sd=>4}, {}]
Я обновил в своем ответе, почему он был назначен второму аргументу.