If you try to call a method on a nil
object in Ruby, a NoMethodError
exception arises with the message:
"undefined method ‘...’ for nil:NilClass"
However, there is a try
method in Rails which just return nil
if it's sent to a nil
object:
require 'rubygems'
require 'active_support/all'
nil.try(:nonexisting_method) # no NoMethodError exception anymore
So how does try
work internally in order to prevent that exception?
ActiveSupport 4.0.0 defines two try
methods: one is for Object
instances:
class Object
def try(*a, &b)
if a.empty? && block_given?
yield self
else
public_send(*a, &b) if respond_to?(a.first)
end
end
end
the other is for NilClass
instances (nil
objects):
class NilClass
def try(*args)
nil
end
end
Now, suppose we have an Object
instance (excluding nil
, which actually inherits from Object
, like everything else in Ruby), defining a method which returns nil
:
class Test
def returns_nil
nil
end
end
So, running Test.new.try(:returns_nil)
or Test.new.not_existing_method
, Object#try
gets called, which checks if a public method exists (the respond_to?
); if it does it calls the method (the public_send)
, otherwise it returns nil
(there aren't other lines).
If we call another try
on of these returning nil
methods:
Test.new.try(:returns_nil).try(:any_other_method)
Test.new.try(:not_existing_method).try(:any_other_method)
we call NilClass#try
, which is nil#try
, which simply ignores everything and returns nil
. So any other try
is called on a nil
instance and returns nil
.