GriwMF
GriwMF

Reputation: 279

How define_method uses variables initialised outside of it

class Temp1
  def add(s)
    match = 'test'
    self.class.class_eval do
       define_method(s) do
         puts match
       end
    end
    #match ='haha'
  end
end

As i thinks of it, 'match' is a local variable, so i don't understand how it can see it from another method, plus if uncomment #match ='haha', method will print 'haha' somehow. Can somebody explain it?

Also, i don't see difference here between using class_eval or instance_eval, seems like it do the same thing.

And, at last but not least, can I create class method here using define_method? So I can call it like Temp1.something instead of Temp1.new.something?

Upvotes: 2

Views: 1288

Answers (1)

Arup Rakshit
Arup Rakshit

Reputation: 118271

Because blocks (do...end) are closures and have access to their surrounding scope.

You used block with class_eval,so it has the access to its surroundings,which is the scope of the method add. Now you use another block with define_method,which as also has the access to the scope of the method add,via the block with the class_eval.match local variable has been created inside the scope of the method add. So the blocks has the access to the variable.

And, at last but not least, can I create class method here using define_method?

No you can't.define_method Defines an instance method in the receiver.self.class is Temp1. Now under Temp1.class_eval do..end,you are defining instance methods of the class Temp1,with the method define_method.define_method is a private class method of all the classes,in which ancestor chain Object class present.

class C;end
C.private_methods.grep(/define_/)
# => [:define_method]

Also, i don't see difference here between using class_eval or instance_eval, seems like it do the same thing.

Okay! Let me explain for you. You can't see the difference here,as Teamp1 is a Class and also an instance of a Class. In both call class_eval and instance_eval,self is being set to Teamp1,by their respective definition as documented.

class C
  def self.bar;11;end
  def baz;12;end
end

C.is_a? Class # => true
C.instance_of? Class # => true

C.class_eval{ bar } # => 11
C.instance_eval{ bar } # => 11

Hope this helps!

Upvotes: 6

Related Questions