1

I have a class with bunch of attributes (first, second, third, etc.). I need to go through all "even" attributes (i.e. second, fourth, sixth, etc.) and make some corrections to just those:

report.first = Calculate('1')

report.second = Calculate('2')
report.second *= 0.9 if requireCorrection && report.second > 5

report.third = Calculate('3')

report.fourth = Calculate('4')
report.fourth *= 0.9 if requireCorrection && report.fourth > 5

report.fifth = Calculate('5')

report.sixth = Calculate('6')
report.sixth *= 0.9 if requireCorrection && report.sixth > 5

# etc.

As you can see, I have the exact same code for each "even" attribute, except for the different attribute name. Is there a way to avoid this repetition in the code (I have around 50 attributes in total)?

8
  • What is Calculate? Commented Jul 8, 2017 at 11:42
  • 1
    More importantly, what is your real goal? You might not need such a construct at all. Commented Jul 8, 2017 at 11:45
  • What does this have to do with pass-by-reference? I notice that you accepted an answer which has nothing to do with pass-by-reference. Commented Jul 9, 2017 at 9:43
  • @JörgWMittag typical Ruby behaviour does not allow to pass object to function, but solution were provided - solve this task. Commented Jul 9, 2017 at 14:00
  • "typical Ruby behaviour does not allow to pass object to function" – What do you mean? That's pretty much the only thing you can do in Ruby. Commented Jul 9, 2017 at 16:54

1 Answer 1

1

You can use Object#send to invoke an arbitrary method on report by specifying the method name as a string or a symbol:

def make_correction(report, which_method)
  current_value = report.send(which_method)
  current_value *= 0.9 if current_value > 5
  report.send "#{which_method}=", current_value
end

The method names first, second, third, etc. do not easily lend themselves to automatization, but if you renamed the methods to item_1, item_2, etc., you could use a loop to process all of them:

(1..50).each do |i|
  report.send "item_#{i}=", Calculate(i.to_s)

  if i.even?
    make_correction(report, "item_#{i}") if require_correction
  end
end

If the method names need to stay the same, you can still simplify the code like this:

attrs = [:first, :second, :third, :fourth, :fifth]

attrs.each_with_index do |attr, ix|
  i = ix + 1  # indexes are zero based, we need to adjust them

  report.send "#{attr}=", Calculate(i.to_s)

  if i.even?
    make_correction(report, attr) if require_correction
  end
end
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, that exactly that I searched for!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.