# Dynamic variables in loop

I have this working code. I think this must be easier with a while loop.

if not c.e1.nil?
extrapreis = number_to_currency Extra.find(c.e1).aufschlag, :unit=>"EUR "
array.push Extra.find(c.e1).name + " (" + extrapreis.to_s + ")"
extpreis = extpreis + Extra.find(c.e1).aufschlag
end
if not c.e2.nil?
extrapreis = number_to_currency Extra.find(c.e2).aufschlag, :unit=>"EUR "
array.push Extra.find(c.e2).name + " (" + extrapreis.to_s + ")"
extpreis = extpreis + Extra.find(c.e2).aufschlag
end
if not c.e3.nil?
extrapreis = number_to_currency Extra.find(c.e3).aufschlag, :unit=>"EUR "
array.push Extra.find(c.e3).name + " (" + extrapreis.to_s + ")"
extpreis = extpreis + Extra.find(c.e3).aufschlag
end
if not c.e4.nil?
extrapreis = number_to_currency Extra.find(c.e4).aufschlag, :unit=>"EUR "
array.push Extra.find(c.e4).name + " (" + extrapreis.to_s + ")"
extpreis = extpreis + Extra.find(c.e4).aufschlag
end
if not c.e5.nil?
extrapreis = number_to_currency Extra.find(c.e5).aufschlag, :unit=>"EUR "
array.push Extra.find(c.e5).name + " (" + extrapreis.to_s + ")"
extpreis = extpreis + Extra.find(c.e5).aufschlag
end


It is always the same code, except for the variable e (1, 2, 3, 4, 5). How can I put this in a while loop and put the counter together with e?

(1..5).each do |i|
e = c.send("e#{i}")
next if e.nil?
found = Extra.find(e)
array.push("#{found.name} (#{number_to_currency(found.aufschlag, unit: "EUR ")})")
extpreis += found.aufschlag
end


If you can be certain that c.e1 etc. never becomes false, then:

(1..5).each do |i|
next unless e = c.send("e#{i}")
found = Extra.find(e)
array.push("#{found.name} (#{number_to_currency(found.aufschlag, unit: "EUR ")})")
extpreis += found.aufschlag
end

• Thank you very much. So I learn a little more about rails ;)
– user1953483
Jan 6, 2013 at 21:40
• It is not Rails. It's all plain Ruby. Actually, I barely know anything about Rails.
– sawa
Jan 6, 2013 at 21:42

[c.e1, c.e2, c.e3, c.e4, c.e5].each do |e|
if e
extrapreis = number_to_currency(Extra.find(e).aufschlag, unit: 'EUR ')
array << Extra.find(e).name + ' (' + extrapreis.to_s + ')'
extpreis += Extra.find(e).aufschlag
end
end

• Maybe unless instead of if !? Jan 6, 2013 at 21:17
• I don't like unless, especially at the start of a conditional block. It's one of those programmer-choice, often argued, syntax things. Jan 6, 2013 at 21:20
• Fair enough - in fact this article would advocate a simple if e instead :) Jan 6, 2013 at 21:24
• That's true, if e is how I'd normally write it if I was doing a refactor or review. :-) I'll adjust it. Thanks. Jan 6, 2013 at 21:36
• You'd probably like Ruby Best Practices Jan 6, 2013 at 21:39

• Use of parentheses: Ruby allows you to drop them, but the community seems to have reached a consensus it may harm readability, restrict its usage to DSL-style code.

• extrapreis: this may be "private" code (well, it's not anymore since you publicly asked about it), but it's good practice to use the commonly accepted language in the programming world (for script names, variable names, comments, everything).

• array.push, x = x + y, ...: you may use this but being aware about functional programming and why inplace updates are considered (by some) bad practice. More on this issue.

• if not c.e1.nil? -> if c.e1.

• Extra.find(c.e1).aufschlag. In each block you call this twice, why? use a variable to store the value.

For a novice programmer a functional approach may be a little difficult to grasp at first, but it introduces important concepts that will (hopefully) prove useful later on:

strings, values = [c.e1, c.e2, c.e3, c.e4].compact.map do |e|
value = Extra.find(e).aufschlag
extra_price = number_to_currency(value, :unit => "EUR")
name = Extra.find(e).name
["#{name} (#{extra_price})", value]
end.transpose
extra_price_total = values.inject(0, :+)