Fun with Ruby’s case/when statements

Ruby’s case statements are pretty cool and more intuitive to the C, C++ counterparts. Each object in the when statement is expected to support the === operator which is invoked with the object given in the case statement. This allows you use Range, Regexp and other objects as long as they support the === operator.

For example all of the following work:

string = "hello"
case string
when /^hello/
    puts "matches first when"
when /^world/
    puts "matches second when"
end

You can also put multiple match criteria within the same when statement in which case the matches are OR‘d. Well, I want to AND them or ideally just define a Proc that specifies a match. The reason is I have a largish case statement and don’t feel like converting them all into if/elsif/end. I was thinking something like would be pretty handy:

case string
when { |x| x =~ /^hello/ & x.size > 5 }
    puts "matches"
end

Well, that doesn’t make the interpreter happy. So here’s another way. First define a matches method that wraps the given block into a Proc and adds the === operator to the eigen class of the object. This just means that are only adding this method to obj and not the Proc class. Remember Ruby classes are open?

def matches &block
    obj = Proc.new(&block)
    class << obj
        def === rhs
            self.call(rhs)
        end
    end
    return obj
end

Using this in case statements is now trivial and it reads pretty nicely too:

case string
when matches { |x| x =~ /^hello/ and x.size > 5 }
    puts "works!"
end

and voila’.

Update: The point wasn’t about fancy regexes and how I could’ve used a better one, but more about using complex boolean expressions in when statements.

Bookmark and Share