Help us understand the problem. What is going on with this article?

Rubyのキーワード引数にto_hashを実装するオブジェクトを渡すとキーワード引数として展開される

TL;DR

Rubyにおいて、キーワード引数を取るメソッドには、to_hashメソッドを実装しているオブジェクトを渡すことができて、キーワード引数として展開して解釈される。

キーワード引数とは

def log(msg, level: "ERROR", time: Time.now)
  puts "#{ time.ctime } [#{ level }] #{ msg }"
end

log("Hello!", level: "INFO")  #=> Mon Feb 18 01:46:22 2013 [INFO] Hello!

(https://magazine.rubyist.net/articles/0041/0041-200Special-kwarg.html より引用)

このlogメソッドのleveltimeみたいな感じで、引数にデフォルト値を指定することができて、また名前を指定して引数を渡せるという便利機能です。

Hashはキーワード引数に展開される

キーワード引数にはHashを渡すことができて、その場合はHashの中身が展開されます

# 普通の使い方
log('aaa', level: 'AAA') # => Wed Nov  6 09:16:36 2019 [AAA] aaa
# Hashも渡せる
log('aaa', {level: 'AAA'}) # => Wed Nov  6 09:16:44 2019 [AAA] aaa

このようなHash => keyword引数の変換はRuby 2.7ではdeprecatedになったので注意してください 1

Hash以外もキーワード引数にわたす

そして、キーワード引数に渡して展開されるのはHashだけではありません。「to_hashを実装しており、かつその返り値のkeyがsymbolであるオブジェクト」ならなんでも展開されます。

# to_hashを実装しているクラス
class HogeWithToHash
  def to_hash
    { level: 'AAA' }
  end
end

# キーワード引数として展開される
log('aaa', HogeWithToHash.new) # => Wed Nov  6 09:27:25 2019 [AAA] aaa

# to_hashを実装しているが返り値のHashのkeyが文字列であるクラス
class HogeWithToHashStringKey
  def to_hash
    { 'level' => 'AAA' }
  end
end

# キーワード引数として正しく展開されない
log('aaa', HogeWithToHashStringKey.new) # => ArgumentError (wrong number of arguments (given 2, expected 1))

キーワード引数に展開されるオブジェクトの例: Rake::TaskArguments

このような条件を満たすオブジェクトとして、Rakeタスクを定義するときに使われる Task::Arguments が挙げられます。したがって、以下のRakefileは正しく動きます:

def greet(first_name:, last_name:)
  puts "Hello, #{first_name} #{last_name}"
end

task :greet, [:first_name, :last_name] do |t, args|
  greet(args)
end
$ rake "greet[Ichiro,Tanaka]"
Hello, Ichiro Tanaka

以上

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした