A word of warning:

This is heavy ruby abuse. It even got the Evil of the Day Award™ from zenspider.

Thou shalt not use alias_method_chain!

What it does

Chainable is an alternative to alias_method_chain, that uses inheritance, rather than aliasing. It does the following when “chaining” a method:

  • copy the original method to a new model

  • include the model

  • overwrite the method

Thus you can use super and keep your method list clean, too! It even supports a (rather dangerous) auto chaining mode, so you do not have to explicitly chain a method, but chain a method whenever it would be overwritten instead.

Example:

class Foo

  def foo
   10
  end

  # now chain to foo
  chain_method :foo do
    super + 3
  end

  # or turn on auto chaining
  auto_chain do

    def bar
      10
    end

    def bar
      super + 1
    end

    def bar
      super ** 2
    end

  end

  # or chain multiple methods at once
  chain_method :foo, :bar do
    super.to_s
  end

end

f = Foo.new
puts f.foo # => 13
puts f.bar # => 121

Of course you can do this with any class (or module):

Array.class_eval do
  chain_method :each
  def each
    return super if block_given? or RUBY_VERSION >= "1.8.7"
    MyStuff::Enumerator.new self, :each
  end
end

Note that there is a speed advantage when using chain_method without a block and doing a “def”, since chain_method will use define_method if a block is given, which produces slower methods (but makes the method a real closure).

Benchmark

chain_method tends do produce slightly faster methods than alias_method_chain:

                                         user     system      total        real
chainable (define_method)            0.160000   0.010000   0.170000 (  0.183363)
chainable (def & eval)               0.170000   0.010000   0.180000 (  0.177084)
alias_method_chain (define_method)   0.570000   0.030000   0.600000 (  0.607330)
alias_method_chain (def & eval)      0.170000   0.020000   0.190000 (  0.190048)

Installation

Add github gems, if you haven’t already:

gem sources -a http://gems.github.com

Install gem:

gem install rkh-chainable