user398520
user398520

Reputation: 1663

A ruby test for nil throws an error

  1. x is an Array.
  2. Notice the two comparisons below. The first should produce "true", as expected. The second throws an error. What is going on here?

Why does negative comparison for nil not produce false in the second test?

ruby-1.9.2-p136 :079 > x[2]['comments']['data'][0]['from']['name'] != nil
 => true 

x[2]['comments']['data'][1]['from']['name'] != nil
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
    from (irb):78
    from /Users/justinz/.rvm/gems/ruby-1.9.2-p136/gems/railties-3.0.3/lib/rails/commands/console.rb:44:in `start'
    from /Users/justinz/.rvm/gems/ruby-1.9.2-p136/gems/railties-3.0.3/lib/rails/commands/console.rb:8:in `start'
    from /Users/justinz/.rvm/gems/ruby-1.9.2-p136/gems/railties-3.0.3/lib/rails/commands.rb:23:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

Upvotes: 2

Views: 437

Answers (4)

Mark Byers
Mark Byers

Reputation: 838216

I'd guess it's because the value x[2]['comments']['data'][1] is nil.

You might want to use this helper method instead:

def nullsafe_index(a, keys)
    keys.each{|key|
        return nil if a.nil?
        a = a[key]
    }
    return a
end

Use like this:

nullsafe_index(x, [2, 'comments', 'data', 0, 'from', 'name']).nil?

Upvotes: 2

sarnold
sarnold

Reputation: 104050

Is x[2]['comments']['data'][1] == nil?

Try evaluating each piece of your expression:

x[2]
x[2]['comments']
x[2]['comments']['data']
x[2]['comments']['data'][1]
x[2]['comments']['data'][1]['from']
x[2]['comments']['data'][1]['from']['name']

Upvotes: 0

cam
cam

Reputation: 14222

It looks like x[2]['comments']['data'] doesn't have a second element. This is equivalent to calling nil['from'], which will also raise an exception.

Upvotes: 0

Pan Thomakos
Pan Thomakos

Reputation: 34350

x[2]['comments']['data'][1] is an empty hash, so when you call ['from'] on it, the result is nil, which means calling ['name'] on that result of nil, produces an error. Here's how you can reproduce it:

x = {}
x['from'] #=> nil
x['from']['name'] #=> NoMethodError

You can think of your request as a collection of function calls:

x[2]['comments']['data'][1]['from']['name']
# is equivalent to:
x.[](2).[]('comments').[]('data').[](1).[]('from').[]('name')

If any one of these function calls returns nil you can't make another [] function call on it without getting an error.

Upvotes: 1

Related Questions