It's important in Ruby to remember the distinction between variables and the objects they hold. Simply setting a variable will never change the object referenced by that variable. When you do a += b
, it's just shorthand for a = a + b
. So you're assigning a new value to the variable a, not changing the object that used to be there or changing any other references to that object. So changing the variable time
doesn't change @start
.
In order to assign to an instance variable, you need to actually assign to that instance variable. Here's a way to do what you were looking for:
operation = :+
amount = 12
@start, @end = [@start, @end].map {|time| time.send(operation, amount)}
You'll notice that we're not faffing around with that :add
and :sub
business either — we can just pass the actual name of the message we want to send (I used + in this case, but it could be anything).
If you had a big, dynamically generated list of ivars you wanted to set, it's only a little bit more complicated. The only difference there is that need to get and set the ivars by name.
ivars = [:@start, :@end, :@something_else]
operation = :+
amount = 12
ivars.each {|ivar| instance_variable_set(ivar, instance_variable_get(ivar).send(operation, amount))}