I am trying some ruby metaprogramming and got some confusion with instance_eval().
see below examples
@instance_var = 'instance_var'
local_var = 'local_var'
obj = Object.new
obj.instance_eval { p @instance_var; p local_var }
obj.instance_eval { @instance_var = 'instance_var_in_obj'; local_var = 'local_var_in_obj' }
p @instance_var; p local_var
I expect both of @instance_var and local_var can be pass/modify in block but i got
nil
"local_var"
"instance_var"
"local_var_in_obj"
as result we can share(pass/modify) local vars in instance_val but instance vars are belong to self CAN NOT share.
and about instance_exec:
obj.instance_exec(@instance_var) {|instance_var| p instance_var; instance_var = @instance_var }
=> "instance_var"
@instance_var
=> "instance_var"
now i can pass my outer instance var and still CAN NOT modify it.
@instance_arr = []
obj.instance_exec(@instance_arr) {|instance_arr| instance_arr << 'in_block' }
@instance_arr
=> ["in_block"]
obj.instance_exec(@instance_arr) {|instance_arr| instance_arr = [] }
@instance_arr
=> ["in_block"]
with a instance var of array i can modify my instance var but ONLY within current array object
in summary play instance_eval or instance_exec with local vars not instance vars?
is there some concepts i missed?
After some search and advices from my friend i think i figured out the problem. In ruby there is two
Contextwhen your code runningselfandbinding, when you work withlocal varsormethodwithout setself.xxxfirst thing will be checking is it in yourbindingobject as alocal varif not Ruby will think it's a method then search on yourselfobject to find its definition and invoke it. Think this:That's explained
WHYofinstance_evalas its document saidinstance_evaljust changedselfin the given block and NOT touchbindingso methods will be search on newself, local vals still in samebindingobject.About
instance_execi'm not very sure about this but seems like instance vars(with at prefix vars) it will be search onselfdirectly skip onbinding, so out ofinstance_execyour@instance_arrbelongs to oldselfand ininstance_execblock you got it as a newlocal varin the newbindingof block(block has own scope) but the value of it actually is the reference of@instance_arrso invoke method on the newlocal varsuch likepushit will change both of them because they share sameArray instance, but when you assign a newArray instanceto the newlocal varthey are no longer refer sameArray instancethat's the secondWHY.