Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I declare a method dynamically with method_missing?

I have a ruby program, and I want to accept the user's made up method, and make a new method out of that name. I have tried this:

def method_missing(meth,*args,&block)
  name = meth.to_s
  class << self
    define_method(name) do
      puts "hello " + name
    end
  end
end

And I get the following error:

`define_method': interning empty string (ArgumentError) in 'method_missing'

Any ideas? Thanks.

Edit:

I got it working a different way, but I'm still curious how to do it this way. Here is my code:

def method_missing(meth,*args,&block)
  Adder.class_eval do
    define_method(meth) do
      puts "hello " + meth
    end
  end
  send("#{meth}")
end
like image 547
benmanbs Avatar asked Nov 10 '11 05:11

benmanbs


People also ask

How do you define a method dynamically in ruby?

define_method is a method defined in Module class which you can use to create methods dynamically. To use define_method , you call it with the name of the new method and a block where the parameters of the block become the parameters of the new method.

What is method missing in ruby?

method_missing is a method that ruby gives you access inside of your objects a way to handle situations when you call a method that doesn't exist. It's sort of like a Begin/Rescue, but for method calls. It gives you one last chance to deal with that method call before an exception is raised.


1 Answers

The variable name is not available inside the class definition (class << self) scope. It isn't throwing a NameError because you've overridden method_missing.

To do what you're trying to do, you need to keep the scope with name. In order to do that, you have to only use block-based methods (e.g. class_eval) instead of directly opening the class, so something like this:

def method_missing(meth,*args,&block)
  name = meth.to_s
  eigenclass = class << self; self; end
  eigenclass.class_eval do
    define_method(name) do
      puts "hello " + name
    end
  end
end

But actually, the symbol in meth is quite sufficient — you don't need name at all. (Though you'll still need the above technique either way.) On top of that, though, you want to execute the method immediately. The simplest way would just be to resend the message:

def method_missing(meth,*args,&block)
  eigenclass = class << self; self; end
  eigenclass.class_eval do
    define_method(meth) do
      puts "hello #{meth}"
    end
  end
  send(meth, *args, &block)
end
like image 77
Chuck Avatar answered Oct 11 '22 08:10

Chuck