Sometimes while dealing with API responses, I'll end up writing something like:
what_i_need = response["key"]["another key"]["another key 2"]
The problem with that is, it'll throw an error if, say, "another key"
is missing. I don't like that. I'd be a lot happier if what_i_need
turned up a nil
if something along the process broke.
Is there a more elegant solution than:
what_i_need = nil
begin
what_i_need = response["key"]["another key"]["another key 2"]
rescue Exception => e
end
I also thought about monkey patching NilClass you try to access nil["something"]
it would return nil
, but I'm not sure if that's the best way to go about it either of if it's possible even.
Use Hash#fetch with default value.
h = {:a => 2}
h.fetch(:b,"not present")
# => "not present"
h.fetch(:a,"not present")
# => 2
Without default value it will throw KeyError
.
h = {:a => 2}
h.fetch(:b)
# ~> -:2:in `fetch': key not found: :b (KeyError)
But with nested Hash
like your one you can use :
h = {:a => {:b => 3}}
val = h[:a][:b] rescue nil # => 3
val = h[:a][:c] rescue nil # => nil
val = h[:c][:b] rescue nil # => nil
Ruby 2.0有NilClass#to_h
。
what_i_need = response["key"].to_h["another key"].to_h["another key 2"]
Taking some inspiration from Objective-C's key-value coding system, you can do this with a lightweight DSL to walk a series of keys in an arbitrarily-nested data structure:
module KeyValue
class << self
def lookup(obj, *path)
path.inject(obj, &:[]) rescue nil
end
end
end
h = { a: { b: { c: 42, d: [ 1, 2 ] } }, e: "test"}
KeyValue.lookup(h, :a, :b, :d, 1) # => 2
KeyValue.lookup(h, :a, :x) # => nil
Or if you just want the one-liner:
(["key", "another key", "another key 2"].inject(h, &:[]) rescue nil)
To expand on @Priti's answer a bit, you can use a chain of Hash#fetch
instead of Hash#[]
to return empty hashes till you get to the last in the chain, and then return nil
:
what_i_need = response.fetch('key', {})
.fetch('another key', {})
.fetch('another key 2', nil)
or rely on the KeyError exception being raised (maybe not the best, as exceptions as control flow should be avoided):
what_i_need = begin
response.fetch('key').fetch('another key').fetch('another key 2')
rescue KeyError
nil
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.