Ruby 2.3では、Array
およびHash
にDig
と呼ばれる新しいメソッドが導入されました。新しいリリースについてのブログ投稿で見た例は、不自然で複雑です。
# Hash#Dig
user = {
user: {
address: {
street1: '123 Main street'
}
}
}
user.Dig(:user, :address, :street1) # => '123 Main street'
# Array#Dig
results = [[[1, 2, 3]]]
results.Dig(0, 0, 0) # => 1
トリプルネストフラットアレイを使用していません。これがどのように役立つかの現実的な例は何ですか?
[〜#〜] update [〜#〜]
これらのメソッドは、最もよく尋ねられるRubyの質問の1つを解決します。以下の質問には、20個の重複のようなものがあり、すべてDig
を使用して解決します:
この場合、NoMethodError
参照によるnil
sは、実稼働環境で見られる最も一般的なエラーです。
新しいHash#Dig
を使用すると、ネストされた要素にアクセスするときにnil
チェックを省略できます。ハッシュはデータの構造が不明または不安定な場合に最もよく使用されるため、これを公式にサポートすることは非常に理にかなっています。
例を見てみましょう。以下:
user.Dig(:user, :address, :street1)
Isnotと同等:
user[:user][:address][:street1]
user[:user]
またはuser[:user][:address]
がnil
である場合、これは実行時エラーになります。
むしろ、現在のイディオムである次のものと同等です。
user[:user] && user[:user][:address] && user[:user][:address][:street1]
他の場所で作成されたシンボルのリストをHash#Dig
に渡すのは簡単ですが、後者の構成をそのようなリストから再作成するのはそれほど簡単ではありません。 Hash#Dig
を使用すると、nil
参照を心配することなく、簡単に動的アクセスを実行できます。
明らかにHash#Dig
もずっと短いです。
注意すべき重要な点の1つは、いずれかのキーが判明した場合、Hash#Dig
自体がnil
を返すことです。賢明なデフォルトを提供することをお勧めします。 (期待されるメソッドに常に応答するオブジェクトを提供するこの方法は、 Null Object Pattern と呼ばれます。)
繰り返しますが、あなたの例では、空の文字列または「N/A」のようなものが、意味に応じて異なります。
user.Dig(:user, :address, :street1) || ""
1つの方法は、スプラット演算子を使用して、未知のドキュメントモデルから読み取ることです。
some_json = JSON.parse( '{"people": {"me": 6, ... } ...}' )
# => "{"people" => {"me" => 6, ... }, ... }
a_bunch_of_args = response.data[:query]
# => ["people", "me"]
some_json.Dig(*a_bunch_of_args)
# => 6
深くネストされたハッシュ/配列を使用して作業する場合に役立ちます。これは、たとえば、API呼び出しから返される場合があります。
理論上、別のレベルが存在するかどうかを各レベルでチェックする大量のコードを保存します。 practiseでは、Dig
がエラーを作成する場合があるため、このコードの多くが必要になる場合があります(たとえば、チェーン内の何かがキーなしオブジェクト。)
あなたの質問が実際に本当に有効であるのはこのためです-Dig
は私たちが期待するかもしれない使用法を見ていません。これは、たとえばここでコメントされています: なぜDigについて誰も話さない 。
Dig
でこれらのエラーを回避するには、 KeyDial gemを試してください。これはDig
をラップして、エラーが発生した場合にnil/defaultを返すように強制します。