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.