Readable booleans in Ruby
I was going through the source code of Ryan Bates' gem called mustard when I stumbled upon this code:
module Mustard
module ObjectExtension
def must
Must.new(self)
end
def must_not
Must.new(self, true)
end
end
end
Notice anything?
Must.new(self, true)
This true
tells us nothing, we have to go the Must class definition to find out its responsibility:
module Mustard
class Must
def initialize(subject, negate = false)
@subject = subject
@negate = negate
end
end
end
Ok, now we know it is used for negating.
We can improve the first piece of code by passing a speaking for itself symbol :negate
instead of just passing true
:
Must.new(self, :negate)
Since symbols in Ruby are always true, passing :negate
is equialent to passing true
. But in case of :negate
, the intent is right in front of you, no need to jump to the method's definition.
There is one gotcha though - it won't work in cases where you directly compare your assigned variable to true/false. An example from the same gem:
def _assert(matcher)
if @negate == !!matcher.match?
message = @negate ? matcher.negative_failure_message : matcher.failure_message
Mustard.fail(message)
end
end
Here our @negate
variable (which has a value of :negate
) is being compared directly to true/false. This code won't work as expected, because :negate == true
returns false. You only can use this trick if you do comparisons this way:
if @negate
# ...
end
Now that I'm thinking about it, maybe that's why the trick is not so popular :)
You're the 9793rd person to read this article.