I like to use NullObjects, or, more specifically, Black Hole objects for this sort of thing. Avdi Grimm has blessed us with a great ruby gem for this construct called naught. So for your situation, I'd install the gem and then start by creating my project-specific Null Object:
# add this to a lib file such as `lib/null_object.rb`
require 'naught'
NullObject = Naught.build do |config|
config.define_explicit_conversions
config.define_implicit_conversions
config.black_hole
if $DEBUG
config.traceable
else
config.singleton
end
end
Then, include NullObject::Conversions
where needed and go to town, confidently!
# my_class.rb
require 'null_object.rb'
include NullObject::Conversions
Maybe(params[:input])["name"].to_s.presence || "Name not yet given"
# => "Name not yet given"
The great thing about this Black Hole approach is that there's no extra steps needed for any additional chaining. You simply chain methods together as long as you want under the (confident) assumption that it will turn out well. Then, at the end you convert the value to the expected type and the explicit conversions will give you a basic version of that back if something in the chain returned nil before you expected it to.
Maybe(params[:thing1])[:thing2][:thing3].map(&:to_i).sum.to_i
# => 0
Or, if you prefer, you can use Actual
to convert a Black Hole object back to its actual value:
Actual(Maybe(params[:input])["name"]) || "Name not yet given"
For more on the Null Object pattern, check out Avdi Grimm's post on the subject. All in all it's a great way to gain confidence and stop type checking (and remember, even checking for nil
as with .try()
is type checking!). Duck typing is supposed to free us from type checking!