Odd behavior of the method with optional first hash parameter and keyword_args

I have the following method:

def test(first_param = nil, keyword_arg: nil)
  puts "first_param: #{first_param}"
  puts "keyword_arg: #{keyword_arg}"
end

All of the following calls do what I expect from them:

test(:something)
#=> first_param: something
#   keyword_arg:

test(nil, keyword_arg: :keyword_arg)
#=> first_param:
#   keyword_arg: keyword_arg

test({ first_param: :is_a_hash }, keyword_arg: :is_still_working)
#=> first_param: {:first_param=>:is_a_hash}
#   keyword_arg: is_still_working

But omitting the optional keyword_argand passing the hash as the first argument gives me an error:

test(first_param: :is_a_hash)
#=> test.rb:1:in `test': unknown keyword: first_param (ArgumentError)
#           from test.rb:12:in `<main>'

I expect him to install first_paramin { first_param: :is_hash }and keyword_arghow nil.

It seems to interpret each hash as the arg keyword:

test(keyword_arg: :should_be_first_param)
#=> first_param:
#   keyword_arg: should_be_first_param

This should have set first_paramon { keyword_arg: :should_be_first_param }, leaving keyword_arg nilin my opinion.

Is this a parser error or an expected behavior? Tested on ruby ​​2.3.0 and 2.2.4.


Edit: make the first parameter mandatory, and everything works as I expected:

def test_mandatory(first_param, keyword_arg: nil)
  puts "first_param: #{first_param}"
  puts "keyword_arg: #{keyword_arg}"
end

test_mandatory(first_param: :is_a_hash)
#=> first_param: {:first_param=>:is_a_hash}
#   keyword_arg:

test_mandatory(keyword_arg: :should_be_first_param)
#=> first_param: {:keyword_arg=>:should_be_first_param}
#   keyword_arg:

I would expect that the parameter is optional, will not change the way the parameters are analyzed.

bugs.ruby-lang.org, , kword.

+4
1

, Marc-Andre Lafortune :

, .

, . . , :

def foo(*rest, bar: 42)
end

, bar !

, Ruby , :

  • hash-like
  • ,

= > , .

, . , , :

def foo(a = nil, b: nil)
  p a, b
end
foo(:b  => 42) # => nil, 42
foo('b' => 42) # => {"b" => 42}, nil
+2

Source: https://habr.com/ru/post/1623252/


All Articles