I have written a small ruby function that alters a string variable according to its length. The printout shows that in the function, the variable is altered -- however it is always reset to its default when it is called later in the program.
#ruby variable test
def mrn_value(mrn_length, mrn)
if mrn_length < 7
case mrn_length
when 6
mrn = '0' << mrn
return mrn
when 5
mrn = '00' + mrn
return mrn
when 4
mrn = '000' + mrn
return mrn
when 3
puts mrn
mrn = '0000' + mrn
puts mrn
return mrn
when 2
mrn = mrn.to_s
puts 'mrn of 2 length' #prints 'mrn of 2 length'
mrn = '00000' + mrn
puts 'mrn altered in case statement: ' + mrn #prints 'mrn altered in case statement 0000012'
when 1
mrn = '000000' + mrn
return mrn
end
end
end
mrn = 12
mrn = mrn.to_s
mrn_length = mrn.length
mrn_value(mrn_length, mrn)
puts 'Returned MRN: ' + mrn #prints '12'
What I need is for the returned MRN to be the altered MRN. thoughts?
5 Answers 5
I recommend you read more about why Ruby is 'pass-by-value'. In mrn = 12, mrn is a variable, a pointer that points to an object which is 12 in this case.
When you're passing mrn to mrn_value, you're passing a COPY of that pointer. Now you have 2 pointers pointing to the same object. The moment you do mrn = '00000' + mrn you're telling the second pointer to no longer point to 2 but to whatever else is on the right side. Your original mrn pointer outside of the mrn_value method still points to 2, as you can see.
You can read more on Posts on StackOverflow on why Ruby is 'pass by value'. To give you a simplified version to demonstrate:
a = 1
def will_a_be_changed(a)
a = 2
puts a #=> 2
end
will_a_be_changed(a)
puts a #=> 1
4 Comments
What's wrong with reassigning the value?
mrn = mrn_value(mrn_length, mrn)
Comments
In all lines like:
mrn = '0' << mrn
You are not doing what you thing you're doing. You are creating a new string here and you assign it to a local variable. This local variable was pointing to some string object which has been passed to this method, after this assignment it is pointing to some other object, which is lost after method is executed.
Instead, you need to replace the object this variable is pointing:
mrn.replace('0' + mrn)
or
mrn.prepend('0')
Note this is only possible because strings are mutable, this will not work for Fixnums or Symbols.
Now when this is explained, why not simply use existing string methods like for example rjust?
mrn = '12'
mrn = mrn.rjust(7, '0')
You could do something like this, if I understand your requirements correctly:
#ruby variable test
def mrn_value(mrn_length, mrn)
value = ""
if mrn_length < 7
case mrn_length
when 6
value = '0' << mrn
when 5
value = '00' + mrn
when 4
value = '000' + mrn
when 3
puts mrn
value = '0000' + mrn
puts mrn
when 2
value = mrn.to_s
puts 'mrn of 2 length' #prints 'mrn of 2 length'
value = '00000' + mrn
puts 'mrn altered in case statement: ' + mrn #prints 'mrn altered in case statement 0000012'
when 1
value = '000000' + mrn
end
end
value
end
mrn = 12
mrn = mrn.to_s
mrn_length = mrn.length
mrn = mrn_value(mrn_length, mrn)
puts 'Returned MRN: ' + mrn
Comments
The problem is caused by ruby passing method parameters by value rather than by reference (ish).
If you change mrn to @mrn it'll work. The @ makes it an instance variable which I'm guessing in this case makes it available throughout the module.