define_method

March 23rd, 2008

While we were waiting for March 20th RubyJax meeting to get started, Steve Bristol entertained us with a Ruby quiz. One of the questions was particularly interesting as it had many possible answers. I will paraphrase the question as:

“How many ways are there to add a method to an existing class in Ruby?”

I have cataloged the answers that were tossed out as well as a few I just added.

1 . Open the class and add a new method

class String
  def method_one
    puts 'method 1'
  end
end

"abcde".method_one

2 . Create a singleton method on an instance

s = "12345"

def s.method_two
  puts 'method 2'
end

s.method_two

3 . Use Kernel#method_missing

class String
  def method_missing(name, *args)
    super unless name == :method_three
    puts 'method 3'
  end
end

"abcde".method_three

4 . Use Module#define_method

class String
  def create_method(name, &block)
    self.class.send(:define_method, name, block)
  end
end

"abcde".create_method(:method_four) { puts 'method 4' }
"12345".method_four

5 . A variation of #1 : include a module in the class

module ExtraMethods
  def method_five
    puts 'method 5'
  end
end

class String
  include ExtraMethods
end

"abcde".method_five

6 . A variation of #4 : use Object#instance_eval

String.instance_eval("define_method(:method_six) { puts 'method 6' }")

"abcde".method_six

7 . We could use Kernel#eval to execute any of the above as well; here we will emulate instance_eval with a binding

class String
  def self.get_binding
    binding
  end
end

eval("define_method(:method_seven) { puts 'method 7' }", String.get_binding)

"abcde".method_seven

Any others?

Leave a Reply