How do I dynamically create a local variable in Ruby?
Asked Answered
M

3

10

I am trying to dynamically create local variables in Ruby using eval and mutate the local-variables array. I am doing this in IRB.

eval "t = 2"
local_variables # => [:_]
eval "t"
# => NameError: undefined local variable or method `t' for main:Object
local_variables << "t".to_sym # => [:_, :t]
t
# => NameError: undefined local variable or method `t' for main:Object
Marinate answered 24/7, 2013 at 19:7 Comment(2)
Why are you trying to do that? What's the purpose?Starnes
@SergioTulentsev i asked myself exactly the same question. Most probably the original problem can be solved in a much simpler way.Vivienne
R
13

You have to use the correct binding. In IRB for example this would work:

irb(main):001:0> eval "t=2", IRB.conf[:MAIN_CONTEXT].workspace.binding
=> 2
irb(main):002:0> local_variables
=> [:t, :_]
irb(main):003:0> eval "t"
=> 2
irb(main):004:0> t
=> 2
Radiotherapy answered 24/7, 2013 at 19:23 Comment(2)
What about out of IRB? ruby myfile.rb?Starnes
@SergioTulentsev I'm not sure, TOPLEVEL_BINDING and other binding instances in ObjectSpace don't seem to work.Radiotherapy
M
17

You have to synchronize the evaluations with the same binding object. Otherwise, a single evaluation has its own scope.

b = binding
eval("t = 2", b)
eval("local_variables", b) #=> [:t, :b, :_]
eval("t", b) # => 2
b.eval('t') # => 2
Mudslinger answered 24/7, 2013 at 19:13 Comment(14)
Thanks. How do I get the binding for main Object. Everytime you run b = binding; it gives back a different binding object.Marinate
I was look for the outer binding to change. Not the b binding. When I type in t, it not part of the binding. I have to always type in eval(dosomethingwitht,b)Marinate
@ppone: again, what are you trying to accomplish with that?Starnes
Please see Stefan answer.Marinate
He means why you are trying to dynamically set local variables at all. Your problem can probably be solved differently, without setting local variables dynamically and, above all, without using eval.Vivienne
I was just curious why it was not getting set. Your probably right there is a more efficient way to do it. Getting an answer to this question, helps me understand Ruby somewhat better.Marinate
I still don't see an answer anywhere here as to how, in general, to dynamically create a local variable in the existing context/binding, since binding always creates a new context.Nastassia
@PeterAlfvin binding does not create a new context. It refers to the current context.Mudslinger
So why does eval('var=1',binding) not create a new local variable var? (I saw you're most recent answer referring to Ruby 2.1 ...)Nastassia
@PeterAlfvin It does create var. I do not understand the relation to another answer of mine that you mention.Mudslinger
@PeterAlfvin I thought you were.Mudslinger
Anyway, in your answer to this question, t remains undefined in the current context (i.e. in the context the eval calls are being made).Nastassia
@PeterAlfvin That answer is correct, but is irrelevant to my answer. It is using eval without passing the binding argument, which is what the OP of this question is doing.Mudslinger
Just wanted to make sure you hadn't missed my earlier comment about t not being defined in the current context in your answer. :-)Nastassia
R
13

You have to use the correct binding. In IRB for example this would work:

irb(main):001:0> eval "t=2", IRB.conf[:MAIN_CONTEXT].workspace.binding
=> 2
irb(main):002:0> local_variables
=> [:t, :_]
irb(main):003:0> eval "t"
=> 2
irb(main):004:0> t
=> 2
Radiotherapy answered 24/7, 2013 at 19:23 Comment(2)
What about out of IRB? ruby myfile.rb?Starnes
@SergioTulentsev I'm not sure, TOPLEVEL_BINDING and other binding instances in ObjectSpace don't seem to work.Radiotherapy
V
8

You could set instance variables like this:

instance_variable_set(:@a, 2)
@a
#=> 2
Vivienne answered 24/7, 2013 at 19:13 Comment(3)
The question is not about instance variables.Starnes
That's true but maybe this could also solve the problem the OP has. As already said in my comment on the original question, i expect a much simpler solution to be feasible for the original problem.Vivienne
also as an alternative method don't forget about define_method.Redtop

© 2022 - 2024 — McMap. All rights reserved.