Last week I learned a technique in Ruby so small and useful, I couldn't believe I hadn't come across it before.
Suppose a method doubles as a getter and setter. Pass a value to update a setting, or pass nothing to read it:
module Cloakable
def cloaking(value = nil)
if value
@setting = value
else
@setting
end
end
end
That works until we actually want to set false or nil as a value:
class Spaceship
extend Cloakable
cloaking(true) # Hide.
cloaking(false) # Wave hello.
cloaking(nil) # Clear the setting
cloaking # Check before waving
end
How do I extend the contract of my method to consider that last case without breaking its existing behavior? Checking value.nil? wouldn't solve the whole problem either. An explicit nil and an omitted argument would still look the same.
One way I've seen this done is like so:
module Cloakable
NOT_PROVIDED = Object.new.freeze
def cloaking(value = NOT_PROVIDED)
unless value.equal?(NOT_PROVIDED)
@setting = value
end
@setting
end
end
But we don't have to do all that. Here's the trick:
module Cloakable
def cloaking(value = (nothing_provided = true))
return @cloaking if nothing_provided
@cloaking = value
end
end
Ruby evaluates a default argument expression only when that argument is omitted. And that expression can include an assignment.
If we call setting without an argument, nothing_provided = true runs. The assignment also evaluates to true, making that the default value of value — though we don't use it in this branch.
If we supply any argument, even false or nil, Ruby skips the default expression. It still recognizes nothing_provided as a local variable, but its value is nil because the assignment never ran.
We can now distinguish all four calls:
cloaking(true) # Stores true.
cloaking(false) # Stores false.
cloaking(nil) # Stores nil.
cloaking # Returns the stored value.
I first noticed this in Rails' implementation of index_with:
def index_with(default = (no_default = true))
if block_given?
to_h { |elem| [elem, yield(elem)] } # rubocop:disable Rails/IndexWith
elsif no_default
to_enum(:index_with) { size if respond_to?(:size) }
else
to_h { |elem| [elem, default] } # rubocop:disable Rails/IndexWith
end
end
Ruby gives us a neat way to tell the difference when "a value was supplied" and "nothing was supplied" are different pieces of your method's contract. Sometimes, doing nothing is the wisest thing you can do — even if you need to get into a little argument about it.
byroot originally introduced this in Rails PR #44611, and provided some additional guidance on when to use this pattern:

For more insights into how our engineering team works with Ruby, read the Aha! engineering blog.