At some point every Ruby programmer has written this pattern:
result = case item when String string = item "item is a string: #{string}" when Fixnum, Float num = item "item is a num: #{num}" end
I could use directly the item variable in each when block, but this would make the code harder to read. Wouldn't it be nice if we had the item in a variable with a meaningful name plus and with no boilerplate?
Metaprogramming
We'll take advantage of Ruby's powerful metaprogramming capabilities to design a pattern that describes exactly what we want. This is the best I've come up with:
result = item.is do a String do |string| "item is a string: #{string}" end a Fixnum, Float do |number| "item is a number: #{number}" end end
Implementation
This is how I would write it:
class IsArray < Array def a(*categories, &block) self.push({:categories => categories, :block => block}) end end class Object def is(&block) IsArray.new.instance_eval(&block).detect do |hash| if hash[:categories].any? { |category| category === self } break hash[:block] ? hash[:block].call(self) : nil end end end end