Singleton class and instance variables
Asked Answered
C

3

6

Why does the instance_variables method not show @var_one against the variable a?

a = Object.new

def a.my_eval; yield end

a.my_eval { @var_one = 1 }
a.instance_variables
# => []
instance_variables
# => [@var_one]
Cartage answered 6/5, 2016 at 10:4 Comment(0)
C
8

You should use instance_eval:

a.instance_eval { @var_one = 1 }
=> 1
a.instance_variables
=> [:@var_one]

When you use ordinary eval, you define your instance variable in context of current self, if you do it in irb, it is the main object:

a.eval { self }
=> main

So, you can modify your a.eval method by executing a block in a context of an instance:

def a.eval(&block)
  instance_eval &block  
end

a.eval { @a = 1 }
=> 1
a.instance_variables
=> [:@a]
Consueloconsuetude answered 6/5, 2016 at 10:5 Comment(0)
G
2

If your goal is to set an instance variable programmatically, you can use:

a.instance_variable_set(:@var_one, 1)
Guilbert answered 6/5, 2016 at 10:22 Comment(0)
G
0

You should know the difference between eval and instance eval:

Kernel.eval evaluates a string in the current context or the context of the given binding. It is the method used by IRB to process your input. It allows you to define new variables and methods for the current context.

Object.instance_eval evaluates a string (or the given block) within the context of a certain class instance and allows thus the direct access to class properties without attr or attr_accessor. It allows you to define new methods for a instance.

So :

a.instance_eval { @var_one = 1 }
a.instance_variables
# => [:@var_one]
Gracia answered 6/5, 2016 at 10:25 Comment(1)
@mhaseev defined his own eval, so is not using Kernel.eval. I think the answer is more directly to do with the block's binding and how yield or Proc#call interacts with that binding.Wallacewallach

© 2022 - 2024 — McMap. All rights reserved.