🙄
Ruby の #dig で任意のオブジェクトでも参照できるようにする
Hash#dig や Array#dig は『ネストしたデータを掘り下げて値を取得する』ことができます。
data = { data: { names: ["homu", "mami", "mado"] } }
# data[:data][:names][1] と同じようにアクセスできる
pp data.dig(:data, :names, 1)
# => "name"
data[:data][:names][1] と違って何がよいのかというと『途中で存在しない要素があってもエラーにならない』という利点があります。
data = { data: { names: ["homu", "mami", "mado"] } }
# dig の場合はエラーにならず nil を返す
pp data.dig(:data, :name, 1)
# => nil
# data[:data][:name] が nil を返すので nil[1] でアクセスしようとしてエラーになる
data[:data][:name][1]
# => error: undefined method '[]' for nil (NoMethodError)
他のオブジェクトでも #dig で掘り下げられるようにする
この #dig メソッドなのですが『対象のオブジェクトの #dig メソッドを再帰的に呼び出す』みたな仕組みになっています。
逆に #dig メソッドがない場合はエラーになります。
user = { name: "honu" }
pp user.dig(:name, 1)
# => error: String does not have #dig method (TypeError)
逆に対象にしたいオブジェクトに #dig メソッドを定義しておけば他の #dig から呼び出すことができます。
class String
# String に #dig メソッドを定義しておく
alias_method :dig, :[]
end
user = { name: "honu" }
pp user.dig(:name, 1)
# => "o"
ActiveRecord のモデルクラスも #dig は使えないんですが、次のように #dig メソッドを定義しておけば他の #dig から利用できるようになるので便利かもしれませんね。
class User < ActiveRecord::Base
alias_method :dig, :[]
end
data = { user: User.create(name: "homu", age: 14) }
pp data.dig(:user, :name)
# => "homu"
Discussion