def foo(*args)
  p args
end
# **nilなしだと、キーワード引数がハッシュになってargsに格納される
foo(x: 1)
#=> [{:x=>1}]

# **nilはRuby 2.7以上で使用可能
def bar(*args, **nil)
  p args
end
# **nilがあるとキーワード引数を一切受け取らないため、このメソッド呼び出しはエラーになる
bar(x: 1)
#=> no keywords accepted (ArgumentError)

# キーワード引数ではなく、ハッシュオブジェクトを引数として渡すのはOK
bar({x: 1})
#=> [{:x=>1}]

# ----------------------------------------

# Ruby 2.xでは*付きの引数を使うと別のメソッドに引数をまるごと委譲できた
def foo(*args)
  bar(*args)
end

def bar(a, b, c: 1)
  puts "a=#{a}, b=#{b}, c=#{c}"
end

# fooに渡した引数がそのままbarに委譲される
foo(10, 20, c: 30)
#=> a=10, b=20, c=30

# ----------------------------------------

# Ruby 3.0では上のコードのような方法では引数を委譲できない
foo(10, 20, c: 30)
#=> wrong number of arguments (given 3, expected 2) (ArgumentError)

# ----------------------------------------

# Ruby 2.7以降では通常の引数とキーワード引数を別々に委譲する必要がある
def foo(*args, **opts)
  bar(*args, **opts)
end

# ----------------------------------------

# ...引数を使うと通常の引数とキーワード引数をまとめて委譲できる（Ruby 2.7以降）
def foo(...)
  bar(...)
end

# ----------------------------------------

# Ruby 2.7.3以降では...で委譲する引数の中から先頭のいくつかの引数を取り出せる
def foo(a, ...)
  # 第1引数だけ100倍してbarに渡す
  bar(a * 100, ...)
end

# barは同じなので省略

foo(10, 20, c: 30)
#=> a=1000, b=20, c=30
