Roll Your Own respond_to
Posted on November 27th, 2007 by
Drew Colthorp
While refactoring some ruby code the other day I found myself wanting respond_to-like functionality. Specifically, I was calling a function that would have one of several possible outcomes, and I wanted to handle each in a clean way. Specifically, I wanted syntax like this:
1 2 3 4 5 6 7 8 |
zebra array do |row| row.even do |element| puts "even #{element}" end row.odd do |element| puts "odd #{element}" end end |
I put together a bit of code for doing this, called Multiblock. You could write zebra, with a Multiblock, like so:
1 2 3 4 5 6 |
def zebra(list) list.each_with_index do |element, index| odd_or_even = [:even, &odd][index % 2] yield Multiblock[odd_or_even, element] end end |
Here’s the source code for Multiblock:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
class Multiblock def self.[](*args) new *args end def initialize(*args) _expect *args unless args.empty? end def [](*args) _expect *args self end def method_missing(name, *rest) if !@matched @matched = [@waiting_for, :else].include? name if @waiting_for == name @result = yield *@args elsif :else == name @result = yield @waiting_for, *@args end end @result end private def _expect(waiting_for, *args) @waiting_for = waiting_for.to_sym @args = args @result = nil @matched = false end end |


Leave a Reply