こんにちは、鈴木です。
ActiveSupport では Ruby のコアクラスに多くの拡張を提供しています。
その中に、「core_ext/hash/reverse_merge.rb」で定義されている Hash#reverse_merge があります。(破壊的バージョンの Hash#reverse_merge! もあります。)
Hash#reverse_merge
実装を見てみましょう。
1 2 3 4 5 |
class Hash def reverse_merge(other_hash) other_hash.merge(self) end end |
実装は非常にシンプルです。
以下のコードがあるとします。
1 |
other_hash.merge(hash) |
Hash#reverse_merge を使用すると、次のように書き換えることができます。
1 |
hash.reverse_merge(other_hash) |
Q.何が嬉しいの? A.着目している変数をレシーバにできる
例として、会員サイトでログインしたときに「こんにちは、○○さん」のようなメッセージが出ることが良くあります。
これを実現するヘルパーメソッドを作成してみましょう。
1 2 3 4 5 6 7 8 9 |
# ウェルカムメッセージ (Ex. 'こんにちは、太郎さん') を生成する. def welcome_message(message, options={}) # デフォルト値とマージする. default_options = {name: 'ゲスト'} options = default_options.merge(options) # 表示用のメッセージを構築する. "#{message}、#{options[:name]}さん" end |
Hash#reverse_merge を使用すると、以下のように書き換えることができます。
1 2 3 4 5 6 7 8 9 |
# ウェルカムメッセージ (Ex. 'こんにちは、太郎さん') を生成する. def welcome_message(message, options={}) # デフォルト値とマージする. default_options = {name: 'ゲスト'} options = options.reverse_merge(default_options) # 表示用のメッセージを構築する. "#{message}、#{options[:name]}さん" end |
以下の行が、
1 |
options = default_options.merge(options) |
このように変わりました。
1 |
options = options.reverse_merge(default_options) |
Hash#reverse_merge を使うと、「options.reverse_merge(default_options)」のように着目している変数をレシーバとすることができます。
Ruby2.0のキーワード引数が取って代わるケースもある
上記の例のように、オプショナルな引数をハッシュで受け取り、デフォルト値を reverse_merge する(options.reverse_merge(default_options) する)というパターンは非常に多いですが、今後このようなケースでは Ruby2.0 のキーワード引数で置き換えることができます。(キーワード引数については「Ruby2.0のキーワード引数でオプショナルな引数にまつわる面倒事からさようなら」をご参照ください。)
Hash#reverse_merge 自体が不要になるというわけではなく、「着目している変数をレシーバにできる」という特長を生かせる場所で使われ続けていくことになるでしょう。