そういうことだったんですね

いろいろ調べたり学んだりしたことを忘れないように書き連ねています

Ruby - 2.0.0 の新機能 - キーワード引数

Ruby 2.0.0 の新機能としてキーワード引数というものがあります。
引数名を与えて、引数の順序を気にせず設定できる、というものです。

PythonObjective-C などでも有名ですね

メソッド定義

引数の部分の定義をハッシュリテラルに似た(というかほぼ同じ)形式で指定します。値は引数未指定のデフォルト値となります。

def set_label(text:"",width:200,height:50,alt:"")
  puts "text=%s,width=%d,height=%d,alt=%s" % [text,width,height,(alt.empty? ? label : alt)]
end>

 

メソッド呼び出し

set_label(width:150,height:60,text:"A Text",alt:"An Alternative Text")
#=> text=A Text,width=150,height=60,alt=An Alternative Text

引数の順番を意図的に入れ替えていますが正しく設定されています。

引数をHashのオブジェクトを代入してもOKです。

opt = {width:150,height:60,text:"A Text",alt:"An Alternative Text"}
set_label(opt)
#=> #=> text=A Text,width=150,height=60,alt=An Alternative Text

キーワードが存在しなかった場合

ArgumentErrorが投げられます。ここが後述する疑似キーワード引数との大きな違いかもしれません。

例外にしたくない場合は、**を使用しのこりの引数を受け取ります

def set_label(text:"",width:200,height:50,alt:"",**remain)
...
end

キーワード無しの呼び出しが可能か

かならずキーワードと値をセットで指定しないといけません。キーワード無しの場合は通常の引数通りに順番通りに設定されるということはないようです。

疑似キーワード引数

バージョン1.9でも同等の機能の実装は可能でした。疑似キーワード引数、というものです。

  • メソッドの仮引数をHash1つとし、メソッド内で引数チェックを処理する
    def set_label(opt={})
        text = opt[:text] || ""
        width = opt[:width] || 200
        height = opt[:height] || 200
        alt = opt[:alt] || ""
        alt = alt.empty? ? text : alt
        opt = default_opt.merge(opt)
        puts "text=%s,width=%d,height=%d,alt=%s" % [text,width,height,alt]
    end
    
  • 呼び出し時は キーワード引数「風」に使うか、Hash変数を代入する
    set_label text: "a text"
    #=> text=a text,width=200,height=50,alt=a text
    
    opt = {:text => "hash demo", :alt => "hash alt demo" }
    set_label opt
    #=> text=hash demo,width=200,height=50,alt=hash alt demo
  • 存在しないキーワードが代入されても無視される。エラーとする場合はチェックしないとダメ

APIの公開部を作成する場合などキーワード引数の実装でコード量が減りそうですね