Razor Storm
Razor Storm

Reputation: 12336

.? (existence) operator in ruby?

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

Answers (5)

Milo P
Milo P

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

Ismael
Ismael

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

megas
megas

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

Dave Newton
Dave Newton

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

wintersolutions
wintersolutions

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

Related Questions