Damoon Imani
Damoon Imani

Reputation: 23

How to use value of a string to refer to variables?

Some programmer made a method that gets lots of arguements like this:

def age_entry(age_1, age_2, age_3, age_4, age_5, age_6, age_7, age_8)
end

They could pass an array but simply they didn't. I love automation and hate to repeatedly add these variables to and array like this

ages = [age_1, age_2, age_3 ,..., age_8]

I would like to use metaprogramming or other ways to loop with a for or each methods to add them variables to an array like this:

(1..8).each do |index| do
   ages << "age_" + index #value of age_[index] get saved to ages
end

P.S. I know I can use copy and paste but this is only for doing automation stuff with Ruby.

Upvotes: 1

Views: 59

Answers (3)

Cary Swoveland
Cary Swoveland

Reputation: 110645

Suppose the method is as follows.

def oldest(age_bill, age_barb, age_trixie)
  puts "Barb is #{age_barb} years old"
  [age_bill, age_barb, age_trixie].max
end

oldest(35, 97, 29)
  #=> 97

As well as the calculation in the penultimate line (which the OP wishes to avoid), this method requires knowledge of an individual method argument (age_barb). The following is one way to accomplishing both requirements.

def oldest(age_bill, age_barb, age_trixie)
  puts "Barb is #{age_barb} years old"
  b = binding
  args = method(__method__).parameters.map { |arg| b.local_variable_get(arg[1]) }
  args.max
end
  #=> 97
Barb is 97 years old

Here

args
  #=> [35, 97, 29]

Upvotes: 1

tadman
tadman

Reputation: 211540

"Some programmer" should remember that you can pass in arrays. This sort of method signature is really obnoxious to work with for a multitude of reasons, some of them you've already discovered.

One way to refactor this method and preserve functionality is to just take in varargs:

def age_entry(*ages)
end

Now those values are put in an array for you but you can call the method the same way as before. As a plus you can specify more or fewer entries.

Variables with names like x1, x2 and so on are violations of the Zero, One or Infinity Rule and are a sign you need to think about the problem differently.

Upvotes: 3

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 120990

You don’t need any metaprogramming here. Just splat them:

ages = [age_1, age_2, age_3 ,..., age_8]
#         ⇓ HERE
age_entry(*ages)

If you want to collect age_(1..8) into the array, assuming all local vars are defined, use Kernel#binding:

b = binding
ages = (1..8).map { |i| b.local_variable_get("age_#{i}") }

Upvotes: 1

Related Questions