Techioz Blog

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?