In Ruby 1.9, Enumerable methods return an Enumerator when no block is provided them.
This makes it very convenient to chain methods in what is often called fluid notation.
For example, rather than the usual #each_with_index
, one can use:
[1,2,3].each.with_index{ |e, i| ... }
Plenty of other possibilities along these lines become possible. It's a very powerful technique.
In the same spirit, there is another class that can be used in much the same way for more general purpose methods, namely what Ruby Facets calls a Functor. Also known as a Higher Order Function, it is a function that acts on a function. Essentially, it is defined as follows.
class Functor private(*instance_methods.select { |m| m !~ /(^__|^binding$)/ }) def initialize(&function) @function = function end def to_proc @function end def method_missing(op, *args, &blk) @function.call(op, *args, &blk) end end
Here is an example of it's use is overriding #instance_eval
to return
a Functor when no block is provided.
class Object def instance_eval(*args, &blk) return super if blk or !args.empty? Functor.new do |op, *a, &b| fcall(op, *a, &b) end end end
Now we can call a single method via #instance_eval
using fluid notation
instead of having to open a block.
MyClass.instance_eval.attr :x
Let's consider another use, perhaps one a little more charming this time.
module Enumerable def all Functor.new do |op, *a, &b| map{ |x| x.fcall(op, *a, &b) } end end end [1,2,3].all + 3 #=> [4,5,6]
There are many other similar uses for Functors. Just as Enumerator opens up a great deal of convenience and conciseness for Enumerable methods, Functor can do the same for methods generally.
Written by trans, 2009-09-30