Saturday, October 18, 2008

Module#to_proc h0tness

I don't need this right now, so I'm not putting it into any of the codebases I touch. But if I ever do need it, I haven't thought of a reason yet that I shouldn't pull it in.

describe "Module#to_proc" do
  it "provides a proc that mixes the module into the yielded object" do
    
    # Say you've got some stuff,
    
    stuff = ["jimmy", "jane", Object.new]
    
    # and you want to have all that stuff extend a certain Module.
    
    module Fooable
      def foo() "This #{self.class} is fooing"; end
    end
    
    # stuff.each {|thing| thing.extend Fooable } is just so many
    # characters to type!
    
    # With a little hackery in Module, you can do this.
    
    stuff.each &Fooable
    
    # Now all that stuff will have your module mixed in,
    
    stuff.each {|thing| thing.should be_a_kind_of(Fooable) }
    
    # and have interesting new behavior.
    
    stuff.collect {|o| o.foo }.should == [
      "This String is fooing",
      "This String is fooing",
      "This Object is fooing"]
  end
end

Here's all it takes to make it pass, plus some simple memoization so it's cheaper to call.

class Module
  def to_proc
    @to_proc ||= Proc.new {|o| o.extend self }
  end
end