Rader on Rails

Dispatches from my web development journey.

Stephen Colbert and Truthiness (in Ruby)

Is Stephen Colbert a Rubyist?:

The Colbert Report
Get More: Colbert Report Full Episodes,Video Archive


As part of my Dev Bootcamp prep work, we’ve got to complete a series of code challenges. The latest involved using Regular Expressions to determine whether a particular combination of characters existed within a string.

And while Regular Expressions deserve several posts of their own, these exercises helped me to grasp another important concept in Ruby and programming in general: truthiness and falsiness.

In one sentence, this concept in Ruby can be summed up as such:

“In Ruby only false and nil are falsey. Everything else is truthy (yes, even 0 is truthy).” – Jesse Farmer

The first two methods of this exercise can help explain this concept. I first had to define a method has_ssn? that checks whether a string contains a pattern match of the regular expression. In this case, we’re checking whether a string contains a social security number. The next method grab_ssn would return the SSN if one existed in the string.

Here are the specs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
describe "has_ssn?" do
  it "returns true if it has what looks like a SSN" do
    has_ssn?("please don't share this: 234-60-1422").should be_true
  end

  it "returns false if it doesn't have a SSN" do
    has_ssn?("please confirm your identity: XXX-XX-1422").should be_false
  end
end

describe "grab_ssn" do
  it "returns an SSN if the string has an SSN" do
    grab_ssn("please don't share this: 234-60-1422").should == "234-60-1422"
  end

  it "returns nil if it doesn't have a SSN" do
    grab_ssn("please confirm your identity: XXX-XX-1422").should be_nil
  end
end

I came up with a regex pattern that could match a potential social security number: /\d{3}.\d{2}+.\d{4}|\d{9}/ (put this into Rubular, an awesome tool for getting familiar with regular expressions), and then created a method:

1
2
3
def has_ssn?(string)
  string.match(/\d{3}.\d{2}+.\d{4}|\d{9}/) ? true : false
end

I thought this was a pretty decent line of code. It’s just one line and uses a ternary operator.

Because the method includes a question mark, I thought that it had to explicitly return either a true or false value. Indeed, even the specs above seemed to suggest this, and before I was explicitly returning true or false, I couldn’t get the tests to pass.

To solve grab_ssn, I decided to check the string against has_ssn?, and if has_ssn? evaluated to true, I would return the string, or otherwise, return nil (as the specs outlined).

1
2
3
def grab_ssn(string)
  has_ssn?(string) ? string[/\d{3}.\d{2}+.\d{4}|\d{9}/] : nil
end

Again, another one-line method. I was feeling pretty good about myself.

After passing all the tests to the exercises, I decided to check out some other solutions. I found one that was very elegant and even shorter than the methods I had defined, written by Dev Bootcamp NYC’s founder (so no wonder it was so great). However, his has_ssn? solution confused me a bit:

1
2
3
4
5
6
7
8
9
  SSN_REGEXP = /(\d{3})[-\.]?(\d{2})[-\.]?(\d{4})/

  def has_ssn?(string)
    string.match SSN_REGEXP
  end

  def grab_ssn(string)
    string.match(SSN_REGEXP)[0] if has_ssn?(string)
  end

I understood that SSN_REGEXP is a constant, which was a clever way of saving the regular expression so that he wouldn’t have to type it out every single time he wanted to pass it in as an argument. But I was confused because string.match SSN_REGEXP doesn’t return true or false. It would return the actual match, i.e. has_ssn?("please don't share this: 234-60-1422") returned #<MatchData "234-60-1422" 1:"234" 2:"60" 3:"1422">.

However, in grab_ssn, he uses has_ssn?(string) in a conditional, as if it evaluates to true or false. I asked him what was going on, and here’s what he had to say:

“It passes because all it cares about is whether the return value is truthy or falsy (look these terms up for Ruby, I’m not joking). Everything in ruby is truthy except for false and nil. Which leads to the next question: when there is no pattern match, what does ‪#‎match‬ return?”

Okay, things are starting to make sense. As Jesse Farmer explained, in Ruby, everything is truthy (even 0), except for false and nil.

So to answer the second question, when there is no pattern match, has_ssn? returns nil, which is a falsy object. Therefore, the tests pass, even if the method doesn’t explicitly return true or false.

This then begged the question – when do you want to put a question mark on a method if it doesn’t need to explicitly return true or false? If I had defined has_ssn with no question mark, it would still return the same values. I found this answer on StackOverflow that explains this perfectly:

“A method ending with ‘?’ should return a value which can be evaluated to true or false.”

has_ssn? returns either the object, or nil, and the object can be evaluated to true, while nil can be evaluated to false.

Thus, in grab_ssn, the line string.match(SSN_REGEXP)[0] if has_ssn?(string) makes sense – if has_ssn?(string) is true if has_ssn returns a ‘truthy’ object, and it returns nil if it evaluates to the ‘falsy’ object, nil.

Stephen Colbert isn’t waffling – truthiness is a thing.

Comments