Rails: ハッシュのマージをwith_defaultsメソッドで明快に書こう(翻訳)
Railsは、可読性を高めるためにActive Supportで既存のコアRubyクラスに多くのメソッドを追加することで知られています。Hashクラスのwith_defaultsメソッドもその1つです。with_defaultsメソッドは、別途追加済みのreverse_mergeメソッドのエイリアスなので、この名前が動作を知る手がかりとなるはずです。
reverse_mergeメソッドのソースコードを見るとわかるように、実装は実に簡素です。
🔗 以下のように書くよりも
デフォルト値をHash#mergeで追加する。
user_provided = {q: "Andy", age: 44, limit: 1}
listing_options = {order: "asc", limit: 25}.merge(user_provided)
#=> {:order=>"asc", :limit=>1, :q=>"Andy", :age=>44}
🔗 以下のように書こう
#with_defaultsメソッドを利用する。
user_provided = {q: "Andy", age: 44, limit: 1}
listing_options = user_provided.with_defaults(order: "asc", limit: 25)
#=> {:order=>"asc", :limit=>1, :q=>"Andy", :age=>44}
🔗 そうする理由
この「シンプルな」メソッドが存在する理由は、Webアプリケーションでは、メソッドに渡したコンフィグやオプション引数を処理する機会が多いためです。
with_defaultsを使う方が、Rubyのmergeを使うよりも可読性が高まります。メソッドの意図がwith_defaultsという名前ではっきりわかるので、コードも理解しやすくなり、メンテも容易です。
Railsには、このような形で構文が改善された例が数多くあります。最初のプルリク(#28603)でwith_defaultsエイリアスを追加する根拠となったのは、コードが「Railsらしく書ける」からです。
with_defaultsメソッドで書けば、マージで元のハッシュ値が優先され、該当する値がない場合は優先順位の低いデフォルト値が使われることがメソッド名から明らかになります。
🔗 そうしない理由があるとすれば
RailsフレームワークがRubyのコアクラスに暗黙で「モンキーパッチ」を当てることに反対する人もいます。
しかしRailsのコードベースで作業する場合、フレームワークの実践的な決定(や好み)に逆らって実装すると、作業が面倒になる可能性もあります。
さらに、Railsで当てられた従来のパッチの中には、「Rubyらしい」という理由でRubyそのものに取り込まれたものもあります。このwith_defaultsのようなメソッドの構文や読みやすさは、確実にこのカテゴリに分類されるように感じられます。
概要
原著者の許諾を得て翻訳・公開いたします。