How do I write a ruby method combining keyword arguments with hash?

506 views Asked by At

I am trying to design an api that works like this:

client.entries(content_type: 'shirts', { some: 'query', other: 'more', limit: 5 })

So I have this method in my client class:

def entries(content_type:, query={})
  puts query
end

But I get syntax error, unexpected tIDENTIFIER

I also tried splatting:

def entries(content_type:, **query)
  puts query
end

But I get

syntax error, unexpected ')', expecting =>...ry', other: 'more', limit: 5 })

What's the right way to do this without switching around the order of the arguments. The second argument has to be a hash and I don't want to use a keyword argument as a second parameter

1

There are 1 answers

3
Amadan On BEST ANSWER

The second works in current MRI and JRuby:

def entries(content_type:, **query)
  puts query
end
entries(content_type: 3, baz: 4)
# => {:baz=>4}

The first one can't work because you can't both have keyword arguments and also automatically collect key-value pairs into a hash argument.

EDIT in response to comment:

If you wanted to pass a hash and not collect extra keywords into a hash, then you need to reverse the signature:

def entries(query={}, content_type:)
  puts query
end
entries(content_type: 3)
# => {}
entries({ baz: 4 }, content_type: 3)
# => {:baz=>4}

Or, you can splat your hash:

def entries(content_type:, **query)
  puts query
end
entries(content_type: 3, **{baz: 4})
# => {:baz=>4}

Or, you can make the second argument also into a keyword:

def entries(content_type:, query: {})
  puts query
end
entries(content_type: 3)
# => {}
entries(content_type: 3, query: {baz: 4})
# => {:baz=>4}