Параметр Ruby double splat слишком жадный с аргументом Hash

В Ruby 2.4.1 у меня есть такой метод:

def example(*args, **kwargs)
  p args
  p kwargs
end

Я могу передать позиционные аргументы, которые не являются хэшами просто отлично:

irb(main):001:0> example("Greetings")
["Greetings"]
{}

И если я хочу использовать именованные параметры, это тоже хорошо:

irb(main):002:0> example(something: 42)
[]
{:something=>42}

Но, пытаясь передать хэш в качестве позиционного аргумента, это происходит:

irb(main):002:0> example({something: 42})
[]
{:something=>42}

я хочу *args принять {something: 42} не **kwargs ,

Позиционные аргументы должны быть необязательными, но даже если *args мы arg=nil двойной знак еще слишком жадный:

irb(main):001:0> def example(arg=nil, **kwargs)
irb(main):002:1>   p arg
irb(main):003:1>   p kwargs
irb(main):004:1> end
=> :example

irb(main):005:0> example({"key":"value"})
nil
{:key=>"value"}

irb(main):006:0> example({"key":"value"}, this_is: "in kwargs")
{:key=>"value"}
{:this_is=>"in kwargs"}

Как я могу передать хэш в качестве позиционного аргумента, когда метод принимает ** также?

1 ответ

Решение

Это всегда сложно управлять, потому что **kwargs здесь будет агрессивно завладеть этим хешем. Это также создает некоторую путаницу со стороны вызывающего абонента, так как он должен быть осторожен при вызове, независимо от того, что вы делаете:

# Is this options or the body? It's not clear.
example({ payload: true })

Я бы порекомендовал перейти на что-то более явное, например:

def example(**kwargs)
  body = kwargs.delete(:body)
end

Тогда называя это так:

example(body: { ... }, user: "username", ...)

Если вы можете изложить разрешенные аргументы, даже лучше:

def example(body: nil, user: nil, password: nil)
  # ...
end
Другие вопросы по тегам