tags:

views:

65

answers:

2

I'm trying to figure out how to dynamically create methods

class MyClass
  def initialize(dynamic_methods)
    @arr = Array.new(dynamic_methods)
    @arr.each { |m|
      self.class.class_eval do
        def m(*value) 
          puts value
        end
      end
    }
    end
end

tmp = MyClass.new ['method1', 'method2', 'method3']

Unfortunately this only creates the method m but I need to create methods based on the value of m, ideas?

+2  A: 
define_method(m) do |*values|
  puts value
end
sepp2k
Great, that works but how do I specify value as an optional parameter?
Bob
Oh just add a "*" to it like so? define_method(m) do |*value|
Bob
Right (I just edited it to that effect). Note though that `*value` doesn't mean "value is an optional argument". It means "value is an array containing all the arguments (of which there might be an arbitrary number).
sepp2k
You are correct, thanks.
Bob
+4  A: 

There are two accepted ways:

  1. Use define_method:

    @arr.each do |method|
      self.class.class_eval do
        define_method method do |*arguments|
          puts arguments
        end
      end
    end
    
  2. Use class_eval with a string argument:

    @arr.each do |method|
      self.class.class_eval <<-EVAL
        def #{method}(*arguments)
          puts arguments
        end
      EVAL
    end
    

The first option converts a closure to a method, the second option evaluates a string (heredoc) and uses regular method binding. The second option has a very slight performance advantage when invoking the methods. The first option is (arguably) a little more readable.

molf
Thanks, exactly what I needed.
Bob