One of the more innovative initiatives going on in ruby land is the Waves project. It's yet another open source framework to build ruby-based web applications. This one, as they all do I suppose, claims to be "the next-generation". It's chock full of beautiful concise code. Lambdas rule highly in waves. An implementation of resource based mappings where Resources are first class citizens before even going into the MVC paradigm (if at all necessary) is underway.
Out of this project two little gems have appeared that are just beautiful in their design and implementation. One is Autocode, a ruby library for auto-loading and auto-creation of classes and modules. More information about Autocode is here.
The other, and to me the more fascinating one, is a simple little gem called Functor. It is extensively described here. It was itself based on a recent development by Topher Cyll which resulted in his multi gem.
An example of using Functor straight out of the Waves project:
functor( :normalize, Symbol, Hash ) { | name, options | options.merge!( :name => name ) }
functor( :normalize, String, Hash ) { | p, options | options.merge!( :pattern => p ) }
functor( :normalize, Regexp, Hash ) { | re, options | options.merge!( :pattern => re ) }
functor( :normalize, Exception ) { | exception | { :exception => exception } }
functor( :normalize, Hash ) { | options | options }
It's called like this:
def map( *args, &block )
options = normalize( *args )
...
end
Consider for a moment how this code would look like without Functor. You'd probably end up with a dozen nested if-then-else and/or case-when statements.
So Functor seems to behave like a method overloader. Something that natively exists in languages like java and C++. Matz refuses to implement method overloading in ruby because "orthogonal features [...] can explode into complexity". And I think he's right in that. Functor allows orthogonality to creep in. But if you don't go overboard with this stuff you'd be 'right.
The beauty of Functor however is that it allows more than just method overloading. Method overloading matches on the class of it's arguments. In contrast, Functor matches the arguments first by trying the === operator, then the == operator and if that didn't match it will try using call if you provided a lambda or a Proc (or anything really that responds to :call). So for example, this would be possible:
functor( :get, /^foo$/ ) { |p| "foo!" }
functor( :get, /^bar$/ ) { |p| "bar!" }
Calling get("bar") would return bar!
You can play around with functor by installing it as a gem (source is http://gems.github.com/):
sudo gem install -r functor
Or get the source code at github.
Comments
No comments yet.