I want to write a method which takes one parameter and creates another method, named with this parameter. Here is my code
class Class
def createMethod(attr_name)
attr_name = attr_name.to_s
class_eval %Q{
def #{attr_name}
puts "bar"
end
}
end
end
p Class.new.createMethod("foo").respond_to?(:foo)
Unfortunately, respond_to?(:foo)
evaluates to false
. What's wrong?
This is because class_eval
is a class method and you're calling it in the context of an instance. You can do this instead:
class Class
def createMethod(attr_name)
attr_name = attr_name.to_s
self.class.class_eval %Q{
def #{attr_name}
puts "bar"
end
}
self # Return yourself if you want to allow chaining methods
end
end
Here's the output from irb
when doing this:
irb(main):001:0> class Class
irb(main):002:1> def createMethod(attr_name)
irb(main):003:2> attr_name = attr_name.to_s
irb(main):004:2> self.class.class_eval %Q{
irb(main):005:2" def #{attr_name}
irb(main):006:2" puts "bar"
irb(main):007:2" end
irb(main):008:2" }
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0> clazz = Class.new
=> #<Class:0x007fd86495cd58>
irb(main):012:0> clazz.respond_to?(:foo)
=> false
irb(main):013:0> clazz.createMethod("foo")
=> nil
irb(main):014:0> clazz.respond_to?(:foo)
=> true