Reputation: 15117
Currently I am doing the following, but I am sure there must be a better way:
def birthday_defined?(map)
map && map[:extra] && map[:extra][:raw_info] && map[:extra][:raw_info][:birthday]
end
There may be cases where only map[:extra]
is defined, and then I will end up getting Nil exception errors cause map[:extra][:raw_info]
doesn't exist if I dont use my checked code above.
Upvotes: 4
Views: 241
Reputation: 168101
This should work for you:
def birthday_defined?(map)
map
.tap{|x| (x[:extra] if x)
.tap{|x| (x[:raw_info] if x)
.tap{|x| (x[:birthday] if x)
.tap{|x| return x}}}}
end
Upvotes: 0
Reputation: 17169
This is a little hacky but it will work:
def birthday_defined?(map)
map.to_s[":birthday"]
end
If map
contains :birthday
then it will return the string which will evaluate to true
in a conditional statement while if it doesn't contain :birthday
, it will return nil
.
Note: This assumes the key :birthday
does not appear at potentially multiple locations in map
.
Upvotes: 0
Reputation: 434675
If you're using Rails, then you can use try
(and NilClass#try
):
value = map.try(:[], :extra).try(:[], :raw_info).try(:[], :birthday)
That looks a bit repetitive: it is just doing the same thing over and over again while feeding the result of one step into the next step. That code pattern means that we have a hidden injection:
value = [:extra, :raw_info, :birthday].inject(map) { |h, k| h.try(:[], k) }
This approach nicely generalizes to any path into map
that you have in mind:
path = [ :some, :path, :of, :keys, :we, :care, :about ]
value = path.inject(map) { |h, k| h.try(:[], k) }
Then you can look at value.nil?
.
Of course, if you're not using Rails then you'll need a replacement for try
but that's not difficult.
Upvotes: 1
Reputation: 710
I have two ways. Both have the same code but subtly different:
# Method 1
def birthday_defined?(map)
map[:extra][:raw_info][:birthday] rescue nil # rescues current line
end
# Method 2
def birthday_defined?(map)
map[:extra][:raw_info][:birthday]
rescue # rescues whole method
nil
end
Upvotes: 1
Reputation: 187034
That's idiomatic why to do it. And yes it can be a little cumbersome.
If you want to extend Hash
a bit though, you can do some cool stuff with something like a key path. See Access Ruby Hash Using Dotted Path Key String
def birthday_defined?
map.dig('extra.raw_info.birthday')
end
Upvotes: 0
Reputation: 15089
Use a begin/rescue block.
begin
map[:extra][:raw_info][:birthday]
rescue Exception => e
'No birthday! =('
end
Upvotes: 0