One of the first things you may hear an enthusiastic Rubyist say is: Ruby is pure OO! Everything is an object! Even nil!
Yes, nil is an object. How does that help? One benefit is that nil can have methods. Of interest for this post are the methods that start with to_:
nil.methods.grep /^to_.$/
What do those methods evaluate to?
nil.methods.grep(/^to_.$/).each do |method|
puts "nil.#{method} #=> #{nil.send(method).inspect}"
end
nil.to_i
nil.to_f
nil.to_a
nil.to_s
Now, here's an arbitrary method that demonstrates handling nil:
def upcase(input)
input.to_s.upcase
end
upcase "foo"
upcase "BaR"
upcase nil
The .to_s allows nil to be passed in without failure. Without the .to_s you would receive this:
NoMethodError: undefined method `upcase' for nil:NilClass
Here's where the duck comes in:
upcase String
upcase Object.new
Not only does .to_s allow you to handle nil gracefully, it allows you to pass in any object rather than only strings, which is part of what duck typing is all about.
Although calling .to_s on an argument which you are expecting to be a string may seem pointless, it allows you to handle nil and support the ducks.