Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby class_eval method

Tags:

ruby

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?

like image 528
Bob Avatar asked Jan 10 '10 23:01

Bob


People also ask

What is class_eval Ruby?

class_eval is a method of the Module class, meaning that the receiver will be a module or a class. The block you pass to class_eval is evaluated in the context of that class. Defining a method with the standard def keyword within a class defines an instance method, and that's exactly what happens here.

What is instance_ eval in Ruby?

instance_eval is a similar method on the Object class that takes in Ruby code embedded in a string and two other optional arguments. One of the major differences between eval and instance_eval is that with instance_eval you have the choice of explicitly handling the context of self .

What is metaprogramming in Ruby?

Metaprogramming is a technique by which you can write code that writes code by itself dynamically at runtime. This means you can define methods and classes during runtime.


2 Answers

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.

like image 82
molf Avatar answered Oct 12 '22 17:10

molf


define_method(m) do |*values|
  puts value
end
like image 4
sepp2k Avatar answered Oct 12 '22 16:10

sepp2k