Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ArgumentError with optional parameters

Tags:

ruby

rubocop

Can someone help me with this:

ruby 2.7.3p183

Here is the situation, this method:

def send_request(url, payload = {}, internal_proxy: true)

...

and this call

send_request('random_address', { foo: :bar })

Returns me:

Traceback (most recent call last):
        5: from C:/Ruby27-x64/bin/irb.cmd:31:in `<main>'
        4: from C:/Ruby27-x64/bin/irb.cmd:31:in `load'
        3: from C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
        2: from (irb):4
        1: from (irb):1:in `send_request'
ArgumentError (unknown keyword: :foo)

I understand that it is trying to match the optional parameters, but why? shoudn't 'payload' variable receive the parameter?, I tried to search for an explanation, but I can't seem to find any


I used to use internal_proxy variable just like payload;

def send_request(url, payload = {}, internal_proxy = true)

but rubocop warns me;

Use keyword arguments when defining method with boolean argument.
(convention:Style/OptionalBooleanParameter)

Does hash on the first not optional parameter always count as the keyword argument? If so, how can I get the expected behaviour I mentioned above? (unless is a bad practice for some reason)

Is this a bug, or is there a reason for this??

like image 368
saviu-u Avatar asked May 07 '26 23:05

saviu-u


2 Answers

In Ruby < 3.0, if the last argument is a hash, and the method being called accepts keyword arguments, then it is always converted to keyword arguments.

Ruby 3.0 fixes this.

You should upgrade to Ruby 3.0 if you can, or else think of a different API.

like image 83
Marc-André Lafortune Avatar answered May 10 '26 10:05

Marc-André Lafortune


A possible solution for your problem is to change the order of your parameters as follow:

def send_request(url, internal_proxy: true, **payload)
    p payload
    p 'fooo'
end

send_request('asd', {foo: :bar})
send_request('asd')

The above code should perform the behavior you are looking for. Also, introducing the double splat (**) collects all the extra named keywords as a hash parameter. The first call will print the hash {foo: :bar} and the second call will print an empty hash {} you can try the above snippet here

like image 40
r4cc00n Avatar answered May 10 '26 09:05

r4cc00n



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!