How to avoid NoMethodError for nil elements when accessing nested hashes?

If I try to access a hash element that is not there, I get NoMethodError: undefined method '[]' for nil:NilClass . However, I cannot predict which elements will be present.

 @param_info = {} @param_info["drug"]["name"] # => NoMethodError: undefined method `[]' for nil:NilClass 

How can I avoid raising this error when an element is unexpectedly nil ?

+6
source share
4 answers

If I understand your question correctly, then I make it forgiving if there is no attribute value, you can try the following:

 @param_info.try(:fetch, :drug).try(:fetch, :name) 

It may also return nil , but it will save you the error undefined methods '[]' for nil:NilClass

Update:

To handle keys that do not exist, you can try the following. ( Got this hint from the try equivalent for the hash ):

 @param_info.try(:[], :drug).try(:[], :name) 
+5
source

Ruby 2.3.0 introduced a new method called dig for both Hash and Array , which completely solves this problem.

It returns nil if the element is absent at any nesting level.

 h1 = {} h2 = { a: {} } h3 = { a: { b: 100 } } h1.dig(:a, :b) # => nil h2.dig(:a, :b) # => nil h3.dig(:a, :b) # => 100 

Your usage example would look like this:

 @param_info.dig('drug', 'name') 
+9
source

I would do something like this:

 begin @param_info.fetch(:drug).fetch(:name) rescue KeyError # handle key not found end 

You can do this in one function:

 def param_info_key(info, key1, key2) info.fetch(key1).fetch(key2) rescue KeyError nil end param_info_key({}, :a, :b) # nil param_info_key({a: {}}, :a, :b) # nil param_info_key({a: {b: "foo"}}, :a, :b) # "foo" 

Example:

 irb(main):001:0> s = {} => {} irb(main):002:0> begin irb(main):003:1* s.fetch(:foo).fetch(:bar) irb(main):004:1> rescue KeyError irb(main):005:1> puts "Key not found" irb(main):006:1> end Key not found => nil 
+1
source

You can simply use it if you don't check this:

 irb(main):001:0> def checker(val) irb(main):002:1> unless val.nil? irb(main):003:2> puts 'working on the railroad' irb(main):004:2> end irb(main):005:1> end => nil irb(main):006:0> x = nil => nil irb(main):007:0> checker(x) => nil irb(main):008:0> y = 1 => 1 irb(main):009:0> checker(y) working on the railroad => nil irb(main):010:0> 
0
source

Source: https://habr.com/ru/post/958578/


All Articles