Edited at

ruby引数処理に使えるテクニック

More than 3 years have passed since last update.


nilガード

def nil_guard( val=nil )

val ||= "default"
end

p nil_guard()
# "default"
p nil_guard( "test" )
# "test"

本来nilガードはその変数が未定義でもその場で定義もできちゃうところが強力ですが、引数処理にも使えます.

引数デフォルトにval="default"としてもいいですが、nilが格納された変数が明示的に渡される場面も多いのでnilを防ぎたい局面では有効です.

p nil_guard( false )

# "default"

falseを明示的に引数に渡したいときは注意です.


キーワード引数で必須項目

ruby2.1以降ではキーワード引数の特定の属性を必須化できます.

ラベルの後にデフォルト値を書かなければ必須項目となります.

def required_keyword_args(first_name:, last_name:, age: nil)

"#{first_name}, #{last_name} (#{age.to_s})"
end

p required_keyword_args()
# ArgumentError
p required_keyword_args(first_name: "Isaac")
# ArgumentError
p required_keyword_args(first_name: "Isaac", last_name: "Newton")
# "Isaac, Newton ()"
p required_keyword_args(first_name: "Isaac", last_name: "Newton", age: 30)
# "Isaac, Newton (30)"


可変長引数(アスタリスク)

引数に*をつけると可変長になります.

以下例のように前方から必須化することもできます.

def variadic(arg1, arg2, *others)

p arg1
p arg2
p others
end

variadic(1,2,3,4,5)
# 1
# 2
# [3, 4, 5]
variadic(1,2)
# 1
# 2
# []

引数に**をつけるとキーワード引数をハッシュで受け取ることができます.

def variadic_keyword(arg, *array_args, **hash_args)

p arg
p array_args
p hash_args
end

variadic_keyword(1,2,3,4,5)
# 1
# [2, 3, 4, 5]
# {}
variadic_keyword(1,2,3, april:"spring", july:"summer")
# 1
# [2, 3]
# {:april=>"spring", :july=>"summer"}
variadic_keyword(1,april:"spring", july:"summer")
# 1
# []
# {:april=>"spring", :july=>"summer"}

ちなみに変数定義時ではなく、変数呼び出し時に引数に*をつけると配列を引数として渡すことができます.

**をつければハッシュをキーワード引数として展開できます.

primes = [2,3,5,7,11,13]

variadic(*primes)
# 2
# 3
# [5, 7, 11, 13]

monthes = {april:"spring",may:"spring"}

variadic_keyword(1,2,3,**monthes)
# 1
# [2, 3]
# {:april=>"spring", :may=>"spring"}


stringify_keys

rubyではhashのキーがstringかsymbolかを間違えてはまることがよくあります.

active supportのstringify_keysを使うとハッシュのキーをstringに変換できます.

どちらの形式でもうまく動くようにメソッドが設計されていると親切だと思います.

require "active_support"

require "active_support/core_ext"

def stringify( hash )
hash = hash.stringify_keys
end

p stringify( january:"winter", february:"winter" )
# {"january"=>"winter", "february"=>"winter"}

ネストされたハッシュのキーをstringifyするにはdeep_stringify_keysを使います.


symbolize_keys

stringify_keysの逆をやりたいときはsymbolize_keysです.

require "active_support"

require "active_support/core_ext"

def symbolize( hash )
hash = hash.symbolize_keys
end

p symbolize( "january"=>"winter", "february"=>"winter" )
# {:january=>"winter", :february=>"winter"}

ネストされたハッシュのキーをsymbolizeするにはdeep_symbolize_keysを使います.


with_indifferent_access

active supportのwith_indifferent_accessメソッドを使うと、stringでもsymbolでもアクセスできるハッシュを作成できます.

ハッシュが拡張されたActiveSupport::HashWithIndifferentAccessオブジェクトが返されます.

require "active_support"

require "active_support/core_ext"

def indifferent_access( hash )
hash = hash.with_indifferent_access
p hash[:january]
p hash["january"]
p hash[:february]
p hash["february"]
p hash[:march]
p hash["march"]
end

indifferent_access( "january"=>"1月", "february"=>"2月", march: "3月" )
# "1月"
# "1月"
# "2月"
# "2月"
# "3月"
# "3月"


hash delete

Hash#deleteメソッドは、レシーバのハッシュからデータ削除し、削除されたvalueを返します. この特徴を使って、たとえば1つのキーワード引数集合の中から性質の異なる属性を抜き出すことができます.

def hash_delete( hash )

text_color = hash.delete(:text_color)
p text_color
p hash
end

hash_delete(first_name:"Issaac", last_name:"Newton", text_color:"red")
# "red"
# {:first_name=>"Issaac", :last_name=>"Newton"}

railsのform helperをラップしたメソッドを作って独自オプションを追加したいときなどに便利です.

def custom_text_field( name, value, options={} )

error_message = options.delete :error_message
tag_html = text_field_tag( name, value, options )
wrap_with_validation_error( tag_html, error_message: error_message )
end


assert_valid_keys

active supportのassert_valid_keysは許可するハッシュキーだけを通して、それ以外のものが含まれたら例外を投げます.

require "active_support"

require "active_support/core_ext"

def assert_args( **args )
args.assert_valid_keys(:first_name, :last_name)
end

assert_args( first_name: "Issaac" )
# last_nameが足りないが例外にはならない
assert_args( first_name: "Issaac", last_name: "Newton" )
# 許可リストのキーしか含まないため問題なし
assert_args( first_name: "Issaac", last_name: "Newton", age: 30 )
# 許可リスト以外のキー(age)が含まれるため例外
# Unknown key: :age. Valid keys are: :first_name, :last_name (ArgumentError)


Environment

% ruby -v

ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]

他にも引数処理に使える便利な方法があれば教えてください.