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
No comments:
Post a Comment