LoginSignup
1
1

More than 3 years have passed since last update.

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

Posted at

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

以上

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1