Reputation: 12336
Is there a .?
operator in Ruby that checks if an object is nil
before calling a method on it?
For instance if I have to code:
if person and person.neighbor and person.neighbor.house and person.neighbor.house.rooms
person.neighbor.house.rooms.each do |room|
blah
end
end
Is there a better way than having to do an if check on everything?
And please don't say "code in such a way that these objects cannot ever be nil
", I am getting these things from an API call and can't control it.
Upvotes: 2
Views: 1879
Reputation: 1462
As of Ruby 2.3.0, the &.
"safe navigation" operator does exactly this. So instead of
person and person.neighbor and person.neighbor.house and person.neighbor.house.rooms
you can now just do
person&.neighbor&.house&.rooms
.
http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/
Upvotes: 6
Reputation: 16730
why not
begin
person.neighbor.house.rooms.each do |room|
...
end
rescue NameError
...
end
Exception handlers are made for handle exception :) So if you depend on someone else code, you should not prevent but handle your code for crash, not to check if everything is ok.
Upvotes: 1
Reputation: 21791
For second case, checking for does the object have a list of methods or not, you may use try method
require "active_support/core_ext/object/try"
person.try(:neighbor).try(:house).try(:rooms).each do |room|
blah
end
Or my version of try
class Object
def try(*args, &block)
if args.empty? and block_given?
begin
instance_eval &block
rescue NameError => e
puts e.message + ' ' + e.backtrace.first
end
elsif respond_to?(args.first)
send(*args, &block)
end
end
end
Then you can do it in short way:
person.try{neighbor.house.rooms}.each do |room|
blah
end
Upvotes: 1
Reputation: 160261
Easiest thing to do is use the andand gem, although there are some other, pretty trivially-implemented options, like this, or this, or etc.
Upvotes: 3
Reputation: 5283
The method you are looking for is nil?
Example:
foo.nil?
For a more elegant approaches to programming defensive against nil
values, see my question on the same topic. For example you could write:
person.neighbor.house.rooms.each do |room|
blah
end
rescue false
Upvotes: 1