tags:

views:

94

answers:

3

Using module_eval, my code allows me to dynamically create and add new methods to a class based on input parameters. See this post for an example http://stackoverflow.com/questions/2039826/ruby-classeval-and-yield

Now my question is how do I reset the class back to its original methods? Is there a simple method I can use to reset a class back to it's original state? The reason for this is that once new methods are added to the class, they persists and I need to be get rid of them if I create a new object with a different set of methods.

Also I must apologize if this question doesn't quite make sense, I've been up for 24 hours and probably needed to get some rest to think clearly. If this is not clear, I can provide an example. Thanks for your help in advance.

A: 
Aidan Cully
+1  A: 

I would take one of two tacks:

  • either move the original class methods to a module, which you can re-include later
  • or use module_eval on a subclass of the original class, and just get a new subclass when you want to reset.

The second's a little easier to do:

 subklass = Class.new(MyAwesomeClass)
 subklass.module_eval #...

 # ok, I'm done, I want to reset
 subklass = Class.new(MyAwesomeClass)
rampion
I agree. If you will need to reset the class, then your best bet is to use a subclass. Keep your base class unmodified and create a subclass if you want to dynamically add methods.
bta
+2  A: 

Edit: Added complete solution

If you keep a list of the methods added in your earlier post, you can use remove_method to remove these methods with something like:

class MyTest
  @@methods_list = []

  def self.show_methods
    @@methods_list
  end

  def self.reset_methods
    @@methods_list.each do |method|
      remove_method(method)
    end
    @@methods_list = []
  end

  def self.add_methods
    define_method("method1")  { puts "This is method1" }
    define_method("method2")  { puts "This is method2" }
    true
  end

  def self.method_added(method_name)
    @@methods_list << method_name.to_s
    puts "Added: " + method_name.to_s + ", list: " + @@methods_list.inspect
  end
end

Now you can try out the following:

>> require 'mytest.rb'
>> t = MyTest.new # => #<MyTest:0x2b1e293247f0>
>> MyTest.add_methods
Added: method1, list: ["method1"]
Added: method2, list: ["method1", "method2"]
>> t.method1 # Method is available:
This is method1
>> MyTest.reset_methods
>> t.method1 # Method is undefined now, so we'd expect an error
NoMethodError: undefined method `method1' for #<MyTest:0x2b1e293247f0>
    from (irb):6
Veger
For this solution, there is a method_added(method_name) that you can define that will be called everytime a method is added
blaxter
I tried this but got this error "ArgumentError: wrong number of arguments (2 for 1)", weird.
Bob
Turns out that my error has to do with dynamically generated methods using module_eval not showing up in MyClass, huh.
Bob
What if you use define_method (http://ruby-doc.org/core/classes/Module.html#M001654) to create your dynamic methods? Is remove_method working now?
Veger
define_method yielded the same error
Bob
I added a complete example, complete with the output I got using Ruby 1.8.7
Veger
Thanks Veger, your example code works perfectly, my error before was due to calling self.reset_methods or remove_method from inside the class itself, any idea why that barfed?
Bob