How to assign different variables in loop in ruby? [duplicate] - ruby

This question already has answers here:
How to dynamically create a local variable?
(4 answers)
Closed 7 years ago.
I have list like this:
list = ["test1","test2","test3"]
I want to assign three associated variables with values. Like:
test1_var = "test1"
test2_var = "test2"
test3_var = "test3"
I ran a loop like this and got an error:
list.each { |x| eval(x+"_var") = x}
What is the correct way to do this?

As far as I can tell, it is only possible to dynamically set instance variables and not local variables. So if this is inside a class of some sort, then this will work. If you absolutely don't want them as instance variables in then end, then just assign each to a local version.
list = ["test1","test2","test3"]
list.each { |t| instance_variable_set("##{t}_var".to_sym, t) }
Here is the documentation for instance_variable_set:
http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-instance_variable_set

The block has a different scope of its own. So if you create a local variable within the block, it will not persist beyond the execution of list.each block. Also there are other restrictions as well.
This is almost impossible as per this blog post: http://blog.myrecipecart.com/2010/06/ruby-19-dynamic-creation-of-local.html

Related

Using loop counter as part of a variable's name in Ruby [duplicate]

This question already has answers here:
In Ruby, is there no way to dynamically define a local variable in the current context? [duplicate]
(3 answers)
Closed 7 years ago.
I'm trying to generate a bunch of variables that will be operated on. Started with 2 variables, 4, 8,16 and its about time I put the variable generation in a loop.
The variable is acting as a storage for the index of an array.
So a thread wakes up, picks up a variable and says "variable_0" is the first index, and stores location 24 inside of it.
This is usually done like so. This variable goes on and is used multiple times later on.
variable_0 = get_index(threadid)
Once I have 16 of such variables, its a pain and ugly to see that line repeated more than once. So I thought I'd put in a loop and tried it with 2 methods.
1. EVAL
for i in 0..15 do
eval("variable_#{i} = get_index(threadid)")
end
Does not work at all.
2. instance_variable_set
for i in 0..15 do
index_name = "variable_#{i}"
index_val = get_index(threadid)
instance_variable_set("#{index_name}", :index_val)
end
This doesn't work either, since a later statement prints "variable not found " pretty much.
Is there a good way to go about doing this?
Due to restrictions later down the line, I cannot use an array for this, each variable has to be constructed as a single variable, so no arrays or anything like that would work
As others have pointed out it is not possible to create local variables dynamically in Ruby, you could set up a binding as well if you're looking for another method of achieving this.
With eval
b = binding
10.times do |i|
eval("var#{i} = 'foo'", b)
end
> eval("var1", b)
=> "foo"
> eval("local_variables", b)
=> [:var9, :var8, :var7, :var6, :var5, :var4, :var3, :var2, :var1, :var0, :b, :_]
Without eval
b = binding
10.times do |i|
b.local_variable_set("var#{i}", 'foo')
end
> b.local_variable_get('var1')
=> "foo"
> b.local_variables
=> [:var9, :var8, :var7, :var6, :var5, :var4, :var3, :var2, :var1, :var0, :b, :_]
Your second example is almost valid. You forgot # for instance variable name and you passed a symbol as value instead the value itself.
for i in 0..15 do
index_val = "some value #{i}"
instance_variable_set("#variable_#{i}", index_val)
end
puts #variable_4 # "some value"
https://repl.it/BnLO/6

What does "||=" mean in Ruby? [duplicate]

This question already has answers here:
What does ||= (or-equals) mean in Ruby?
(23 answers)
Closed 7 years ago.
I'm still pretty green when it comes to Ruby and am trying to figure out what this is doing:
command_windows.each {|window| window.hidden ||= window.open? }
The command_windows variable appears to be an array of objects. If someone could explain to me what this line of code means, particularly what the ||= symbol is I would appreciate it.
foo ||= "bar" is the equivalent of doing foo || foo = "bar".
As Mischa explained, it checks for a falsy value before assigning.
In your case, you could think of it as:
command_windows.each {|window| window.hidden || window.hidden = window.open? }
which is another way of saying
command_windows.each {|window| window.hidden = window.open? unless window.hidden }
The ||= operator is used to assign new value to variable. If something was assigned to it before it won't work. It is usually used in hashes, so you don't have to check, if something is already assigned.

Ruby modify hash in "each" block. Pass-by-value subtlety ? [duplicate]

This question already has an answer here:
Ruby - Parameters by reference or by value? [duplicate]
(1 answer)
Closed 8 years ago.
According to this question, ruby is strictly pass-by-value. I came across a case though, which consists of modifying a hash like so:
h = {"one" => ["un", "ein"], "two"=> ["deux", "zwei"]}
h.each { |k,v| v << "overriden"}
resulting in:
{"one"=>["un", "ein", "overriden"], "two"=>["deux", "zwei", "overriden"]}
However, the following behaves differently:
h = {"one" => "un", "two"=> "deux"}
h.each { |k,v| v = "overriden"}
resulting in:
{"one"=>"un", "two"=>"deux"}
How could I have predicted this?
If you read the next paragraph in the answer you linked, it says this:
Ruby doesn't have any concept of a pure, non-reference value, so you certainly can't pass one to a method. Variables are always references to objects. In order to get an object that won't change out from under you, you need to dup or clone the object you're passed, thus giving an object that nobody else has a reference to.
The << operator modifies an array in place. You have a reference to the array, the hash has a reference to that array, and when the array changes, they both point at the same array.
When you use = you are assigning a value to a variable. In a way, you are telling the variable to refer to something else, instead of doing something to the thing the variable references.

What does the |variable| syntax mean? [duplicate]

This question already has answers here:
What are those pipe symbols for in Ruby?
(7 answers)
Closed 2 years ago.
What is the | | around profile below called, what does it mean, and why it is after do? I thought do is followed by a loop block or so.
ticks = get_all[0...MAX].map do |profile|
# ...
end
it's like a foreach, so profile will be a different value in each of the functions calls, one function call per element in get_all.
see this:
my_array = [:uno, :dos, :tres]
my_array.each do |item|
puts item
end
They are part of the syntax for defining a block. The way I like to explain it is that the pipes look like a slide and those variables inside the pipes "slide" down into the block of code below them.
Essentially the variables in the pipes are available to the block. In the case of iteration the variable would represent an element in whatever you are iterating over.
I'll use this example to try to explain the concept to you.
friends = ["James", "Bob", "Frank"]
friends.each { |friend| puts friend }
James
Bob
Frank
So here, we have an array of our friends: James, Bob, and Frank.
In order to iterate over them, we call the #each method on the array. The method will start with the first item in my array and call the block on it.
Essentially, the item that I'm currently iterating over is passed to the variable inside of the two pipe characters. You can call it |buddy| and change the block to { |buddy| puts buddy } and it would still do the same thing.
The pipe characters delimit the parameter list of a block definition just like parentheses delimit the parameter list of a method definition. So, in this code snippet:
def foo(bar, baz) end
some_method_that_takes_a_block do |bar, baz| end
The parentheses and the pipes have the exact same purpose.

Ruby: using strings to dynamically create objects

How do I use strings or symbols to create new variables || objects? Say I want 5 unique objects of an already made item class;
for x in 1..5
item_x = item.new() #where x is obviously the number value of the iterator
end
I have tried using eval() in this manner:
for x in 1..5
eval( "item_" << x << "= item.new()")
end
Hoping that putting the string I want executed into eval would have it executed as if I put it into the code.
I have searched for dynamic object creation and have not found anyone with this problem, sorry if this is mundane stuff. I have found references to people using .const_get and Openstruct but these don't seem to fix my problem in a manner I can understand.
Is there any reason you can't store your objects in an array? That would make them easier to both create and access:
items = []
5.times do
items << Item.new()
end
Then instead of item_1 through item_5, you have item[0] through item[4].
That said, if you really need/want to do the hard thing, instance_variable_set is an option if instance variables (with #) are okay:
for x in 1..5
self.instance_variable_set("#item_#{x}", Item.new())
end
I'd recommend just sticking with the array.
Update: From your comment, it sounds like your actual use case involves desired variable names that aren't consecutive. In that case, I'd use a Hash rather than an Array.
Think of it this way: whatever string you wish to use as the name of a local variable, just use it as a key in a local Hash. I can't think of any instance where that wouldn't be better than what you're trying, even if what you're trying worked.
You can use instance_variable_set to create instance variables in the manner you depict:
for x in 1..5
variable_name = "item_#{x}"
instance_variable_set("##{variable_name}", "value to assign to variable")
end
puts #item_1 #=> "value assigned to item_1"
Note, however, that this will not create local variables.

Resources