Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Rubyのキーワード引数、ハッシュ、スプラットを使いこなす

このようなパターンを見たことがある方は多いのではないでしょうか。メソッドの最後の引数として options ハッシュを受け取り、追加のパラメータをそこに格納するスタイルです。

def hello_message(name_parts = {})
  first_name = name_parts.fetch(:first_name)
  last_name = name_parts.fetch(:last_name)

  "Hello, #{first_name} #{last_name}"
end

残念ながら、この方法ではハッシュからパラメータを取り出す必要があります。つまり、本来やりたい処理にたどり着くまでに、準備のためのコードが大量に挟まってしまうのです。

しかし、Ruby 2.0以降で導入されたキーワード引数を使うようにこのメソッドを書き換えれば、:first_name:last_name をハッシュから取り出す作業は不要になります。Rubyが自動的に処理してくれるからです。

def hello_message(first_name:, last_name:)
  "Hello, #{first_name} #{last_name}"
end

さらに嬉しいことに、アプリケーションがRuby 1.9以降のハッシュ記法を使っているなら、呼び出し側のコードを一切変更せずに、メソッドをキーワード引数へ移行できます。

def hello_message_with_an_options_hash(name_parts = {})
  first_name = name_parts.fetch(:first_name)
  last_name = name_parts.fetch(:last_name)

  "Hello, #{first_name} #{last_name}"
end

def hello_message_with_keyword_arguments(first_name:, last_name:)
  "Hello, #{first_name} #{last_name}"
end

hello_message_with_an_options_hash(first_name: "Justin", last_name: "Weiss")

hello_message_with_keyword_arguments(first_name: "Justin", last_name: "Weiss")

どうですか?これら2つの呼び出しの引数は、完全に同一です!

キーワード引数構文、その先へもう一歩

では、まだ新しいハッシュ記法に移行していない場合はどうでしょうか?すべてのコードを書き換えることも可能です。ただ、少なくともRuby 2.2.1の時点では、古いハッシュ記法でもキーワード引数は問題なく動作します。

irb(main):007:0> hello_message_with_keyword_arguments(:first_name => "Justin", :last_name => "Weiss")
=> "Hello, Justin Weiss"

いいですね!では、引数を個別に渡すのではなく、ハッシュオブジェクトをそのまま渡した場合はどうなるでしょう?

irb(main):008:0> options = {:first_name => "Justin", :last_name => "Weiss"}
irb(main):009:0> hello_message_with_keyword_arguments(options)
=> "Hello, Justin Weiss"

おっと。では、ハッシュとキーワード引数を混ぜて渡したい場合は?

irb(main):010:0> options = {last_name: "Weiss"}
irb(main):011:0> hello_message_with_keyword_arguments(first_name: "Justin", options)
SyntaxError: (irb):11: syntax error, unexpected ')', expecting =>
	from /usr/local/bin/irb:11:in `<main>'

OK、さすがにここまでやると構文エラーになってしまうようです。これを回避するには、Hash#merge を使って単体で渡せるハッシュを組み立てるという手があります。しかし、もっと良い方法が存在します。

キーワード引数ではなく通常の引数であれば、配列を *(スプラット)で展開して渡すことができます。

def generate_thumbnail(name, width, height)
  # ...
end

dimensions = [240, 320]
generate_thumbnail("headshot.jpg", *dimensions)

では、キーワード引数を引数リストに展開(スプラット)することはできるのでしょうか?

実はそれが可能です。鍵となるのが **(ダブルスプラット)です。先ほど失敗した例を ** で修正すると、次のようになります。

irb(main):010:0> options = {last_name: "Weiss"}
irb(main):011:0> hello_message_with_keyword_arguments(first_name: "Justin", **options)
=> "Hello, Justin Weiss"

さらに物好きな人なら、通常の引数・キーワード引数・スプラットをすべて組み合わせることだってできます。

def hello_message(greeting, time_of_day, first_name:, last_name:)
  "#{greeting} #{time_of_day}, #{first_name} #{last_name}!"
end

args = ["Morning"]
keyword_args = {last_name: "Weiss"}

hello_message("Good", *args, first_name: "Justin", **keyword_args) # => "Good Morning, Justin Weiss!"

もちろん、こんな書き方が必要になる状況に陥ったら、もっと早い段階で設計を見直すべきサインかもしれません!

キーワード引数を簡単に受け取る方法

* を使えば、メソッドに渡されたすべての引数をひとつの配列としてまとめて受け取れることはご存じでしょう。

def argument_capturing_method(*args)
  args
end

argument_capturing_method(1, 2, 3) # => [1, 2, 3]

実はこれはキーワード引数に対しても機能します。キーワード引数はハッシュに変換され、args 配列の最後の要素として現れます。

argument_capturing_method(1, 2, 3, key: "value") # => [1, 2, 3, {:key=>"value"}]

とはいえ、この方法で受け取ったキーワード引数を args.last[:key] のように読み取るのはあまりスマートとは言えません。代わりに、新しい ** 構文を使えば、キーワード引数だけを独立して受け取ることができます。

def dual_argument_capturing_method(*args, **keyword_args)
  {args: args, keyword_args: keyword_args}
end

dual_argument_capturing_method(1, 2, 3, key: "value") # => {:args=>[1, 2, 3], :keyword_args=>{:key=>"value"}}

この構文なら、最初の通常引数には args[0] で、:key キーワード引数には keyword_args[:key] で、それぞれ明確にアクセスできます。

…もちろん、これで再びオプションハッシュに戻ってきてしまったわけですが。

キーワード引数は、コードから大量のパラメータ取り出しボイラープレートを取り除いてくれる優れた機能です。しかも、既存のコードをほとんど変更しなくても、その恩恵を受けられる可能性があります。

ただし、より汎用的なメソッドを書くようになると、キーワード引数を適切に扱うために覚えておくべき新しいテクニックがいくつか登場します。日常的に使う機会は多くないかもしれませんが、いざ必要になったときに、このパワーと柔軟性が必ず役立ってくれるはずです。

  1. Rubyでのログ出力をマスターする:LoggerとLogrageの使い方徹底解説

    Rubyでのログ出力入門:LoggerとLogrageの使い方 ロギングは、アプリケーション開発において最も重要なタスクの一つです。ログは以下のような場面で活用されます。 アプリ内部で何が起きているかを把握したいとき アプリケーションを監視したいとき 特定のデータに関するメトリクスを収集したいとき 新しいプログラミング言語を学ぶ際、最初に選ばれるのはその言語がネイティブに備えているロギング機構でしょう。標準機能は通常、扱いやすく、ドキュメントも充実しており、コミュニティでも広く使われています。 ただし、ログデータの内容や扱い方は、企業の方針、ビジネスの性質、アプリケーションの種類に

  2. Vue、Vuex、Railsを使用したフルスタックアプリケーションの構築

    スケーラビリティを念頭に置いてフルスタックアプリケーションを構築することは、特に、完全なタイプスクリプトをサポートする最新バージョンのVueおよびVuexを使用して構築する場合、威圧的になる可能性があります。この記事では、不健康な家畜への治療の処方を管理するCRUDアプリケーションを探索することで、APIリクエストとデータベースの相互作用を処理するVuex4.0を使用した状態管理からスケーラブルなフルスタックアプリケーションを構築するために知っておく必要のあるすべてを読者に教えます。バックエンドはRailsで構築され、フロントエンドによる統合のために基本的なCRUDAPIを公開します。 ほと