1

Below is my snippet which i tried,

class Person
  def test(arg)
    self.class.instance_eval do
      define_method(arg) {puts "this is a class method"}
    end
  end
end

irb(main):005:0> Person.new.test("foo")
=> #<Proc:0x9270b60@/home/kranthi/Desktop/method_check.rb:4 (lambda)>

irb(main):003:0> Person.foo
NoMethodError: undefined method `foo' for Person:Class

irb(main):007:0> Person.new.foo
this is a class method
=> nil

Here am adding a method to the Person class dynamically using instance_eval and define_method. But why is this behaving as instance method?. Is that completely dependent on self? Confused. Can anyone explain me or a reference link also appreciated.

Kranthi
  • 1,377
  • 1
  • 17
  • 34

1 Answers1

1

It's because define_method defines instance method of the receiver. Your receiver (self) is Person class, so it defines instance method of Person class. You can achieve what you want accessing to Person's metaclass:

def test(arg)
  class << self.class
    define_method(arg) { puts 'this is a class method' }
  end
end

I haven't tested it, but it should work.

Marek Lipka
  • 50,622
  • 7
  • 87
  • 91
  • So even if I use self.class.instance_eval it doesn't matter is it!!?? – Kranthi Jan 08 '15 at 14:06
  • But instance _eval also will do the same thing right? it adds the method to meta_clas right? – Kranthi Jan 08 '15 at 14:11
  • 1
    No, `instance_eval` executes provided block in the context of the object it was called on (also, it sets 'current class' to be metaclass of this object, but it doesn't matter here, since `define_method` work on `self`). For example, `Person.instance_eval` executes block in the context of `Person` object. – Marek Lipka Jan 08 '15 at 14:13
  • @Kranthi it's because, like I wrote, `define_method` defines instance method of the receiver (and not of 'current class'). Receiver is `Person`, so it defines instance method of `Person`. 100% agrees with documentation. – Marek Lipka Jan 08 '15 at 14:18