Ruby スタイル: ネストされたハッシュ要素が存在するかどうかを確認する方法
概要
ハッシュに保存された「人」について考えてみましょう。 2 つの例は次のとおりです。
fred = {:person => {:name => "Fred", :spouse => "Wilma", :children => {:child => {:name => "Pebbles"}}}}
slate = {:person => {:name => "Mr. Slate", :spouse => "Mrs. Slate"}}
「person」に子供がいない場合、「children」要素は存在しません。したがって、スレート氏の場合、両親がいるかどうかを確認できます。
slate_has_children = !slate[:person][:children].nil?
では、「スレート」が「人」のハッシュであることがわからない場合はどうなるでしょうか?考慮する:
dino = {:pet => {:name => "Dino"}}
もう子どもの有無を簡単に確認することはできません。
dino_has_children = !dino[:person][:children].nil?
NoMethodError: undefined method `[]' for nil:NilClass
では、特にハッシュが深くネストされている場合 (ここで提供されている例よりもさらに深い場合)、ハッシュの構造をどのようにチェックすればよいでしょうか?おそらくもっと良い質問は、これを行うための「Ruby の方法」は何ですか?ということです。
解決策
これを行う最も明白な方法は、単に各手順を確認することです。
has_children = slate[:person] && slate[:person][:children]
.nil を使用しますか?実際に必要となるのは、プレースホルダ値として false を使用する場合のみであり、実際にはこれはまれです。通常は、単純に存在をテストできます。
そうでない場合は、これを大幅に簡素化できる独自のハッシュ「dig」メソッドを定義することもできます。
class Hash
def dig(*path)
path.inject(self) do |location, key|
location.respond_to?(:keys) ? location[key] : nil
end
end
end
このメソッドは各ステップをチェックし、nil への呼び出しでつまずくのを防ぎます。浅い構造の場合、ユーティリティはある程度制限されますが、深くネストされた構造の場合、非常に貴重であることがわかります。
has_children = slate.dig(:person, :children)
たとえば、:children エントリが実際に設定されているかどうかをテストするなど、これをより堅牢にすることもできます。
children = slate.dig(:person, :children)
has_children = children && !children.empty?