This would allow some cleaner expressions by allowing us to remove some outer parentheses.
This:
def one_of(possibilities = [])
(possibilities.find(&:present?) || "").split(",").first.try(:strip) || ""
end
Becomes:
def one_of(possibilities = [])
possibilities.find(&:present?).or_else("").split(",").first.try(:strip).or_else("")
end
This code would go into Object
and NilClass
. Perhaps something like this:
class Object
def or_else(default_value)
present? ? self : default_value
end
end
class NilClass
def or_else(default_value)
default_value
end
end
edit 1:
I’d also propose having a block variant as well. This would make the API a bit more useful, and a bit more like the inverse of the try
API.
Similar to how we can have:
Person.find_by(name: params[:name]).try do |person|
# do things with person
end
We would be able to handle the non-existing case:
Person.find_by(name: params[:name]).try(:touch).or_else do
MissingPersonReportJob.perform_later(params[:name])
end
Also, try
+ or_else
is useful for non-activerecord objects. Whereas ActiveRecord has APIs such as find_or_create_by
, plain objects can have or_else
.
Slightly contrived, but an example would be:
DEFAULT_VALUES = { a: 1, b: 2 }
# Process a JSON response from an external API.
# Necessary since we don't own the API and can't
# make changes directly to it
# @param [Hash, NilClass] hash
def process_a_json_response(hash)
hash.try(:merge, DEFAULT_VALUES)
.or_else(DEFAULT_VALUES)
end