Automatic inclusion of useful modules in Ruby

Posted by sjs
on Friday, March 30

Then I thought why not do something similar in Ruby too? By sheer luck I was just messing around with Module#method_added and it’s dead easy to implement. method_added isn’t documented online but it receives one argument, which is the Symbol corresponding to the new method’s name.

Here’s something I just put together. It’s neither eloquent nor useful but it illustrates the idea.

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
class Module
  @@magic_methods = {}

  def magic_method(id)
    id = id.to_sym
    @@magic_methods[id] = self
    puts "magic method registered: #{id.inspect} => #{self.inspect}"
  end

  def method_added(id)
    puts "magic method for #{id.inspect}? #{@@magic_methods[id].inspect}"
    return unless @@magic_methods.has_key?(id)
    class_eval do
      include @@magic_methods[id]
    end
  end
end

module Bar
  magic_method :foo
  
  def bar
    foo << ' bar!'
  end
end

class Foo
  def foo
    'foo?'
  end
end

foo = Foo.new
puts foo.bar

Then presumably one could code the following:

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
module Enumerable
  magic_method :each
  
  ...
end

module Comparable
  magic_method '<=>'
  
  ...
end

class MyClass
  def each
    ...
  end

  # at this point Module#method_added includes Enumerable in the context of MyClass

  ...

  def <=>(other)
    ...
  end

  # at this point Module#method_added includes Comparable in the context of MyClass

end

Is this more difficult than just writing include Enumerable? Maybe.

Would it annoy some programmers? Yes.

Is it still pretty sweet? Hell yes!

Comments

Leave a response