1

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 Answers5

2

What's wrong with reassigning the value?

mrn = mrn_value(mrn_length, mrn)

rohit89
  • 5,745
  • 2
  • 25
  • 42
2

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')
BroiSatse
  • 44,031
  • 8
  • 61
  • 86
  • thanks for the suggestion -- i tried using mrn.rjust, but for some reason in that format it does not write to the .csv that I am having store results. it does save them in the other format. *shrugs* –  Oct 08 '14 at 14:27
2

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
Community
  • 1
  • 1
daremkd
  • 8,244
  • 6
  • 40
  • 66
  • Thanks for the explanation & the example. I thought that the "return" command would cause the altered variable to be available outside of the function, am I mistaken? –  Oct 08 '14 at 02:29
  • Ruby is pass-by-value, not pass-by-reference. You cannot pass variables, variables aren't objects. You can only pass objects. – Jörg W Mittag Oct 08 '14 at 08:16
  • 1
    @Elisa - that will work if you follow rohit89's example below. You'll have to reassign it to mrn. – Phil Oct 08 '14 at 10:23
  • @Phil Oh, I see. I'm used to doing this in PHP, where I would 'return' a value for use and have it be assigned already. –  Oct 09 '14 at 15:06
1

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 
steve_gallagher
  • 3,778
  • 8
  • 33
  • 51
0

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.

Community
  • 1
  • 1
Phil
  • 3,568
  • 3
  • 34
  • 40