Strange error in ruby 1.9.1

Hello all,

I just compiled ruby 1.9.1 from source on my computer (osx snow
leopard), and I’m going through the old ruby quiz exercises for fun. I’m
on the secret santa one, and I wrote the code that determines that each
persons secret santa does not have the same last name, to ensure that
each person has to get a gift for someone from a different family. The
quiz is listed here:

http://rubyquiz.com/quiz2.html

My code runs fine most of the time. However, occasionally I’ll get a
strange “undefined method” error. See the code below and sample output:

class Person
attr_accessor :first, :last, :recipient
def initialize(first, last)
@first = first
@last = last
@recipient = nil
end
end

a = [ giant listing of names in the format of “first last” ]

santa_array = [] # instantiate an empty array
a.each do |full_name|
split_array = full_name.split
my_person = Person.new(split_array[0], split_array[1])
santa_array.push(my_person)
end

recipient_array = Array.new(santa_array)
santa_array.shuffle!
recipient_array.shuffle!

santa_array.each do |element|
index = 0
while element.recipient == nil
if element.last != recipient_array[index].last # if the last names
are different, process
element.recipient = recipient_array[index]
recipient_array.delete_at(index)
else
index += 1 # else the last names are the same, loop again on index
+= 1
end
end
end

santa_array.each { |element| puts "#{element.first} #{element.last},
recipient == #{element.recipient.first} " +
“#{element.recipient.last}” }
puts “\n\n”
puts “santa_array.count == #{santa_array.count}”
puts “recipient_array.count == #{recipient_array.count}”

And here’s some sample output:
brandentanga$ ./secretSanta.rb
./secretSanta.rb:67:in block in <main>': undefined method last’ for
nil:NilClass (NoMethodError)
from ./secretSanta.rb:64:in each' from ./secretSanta.rb:64:in
brandentanga$ ./secretSanta.rb
luke skywalker, recipient == lando calrissian
darth vader, recipient == han solo
anakin skywalker, recipient == jeanluc piccard
… so on and so forth, continuing to print properly…

As you can see from the above output, I ran my code twice, with no
modifications, all names are hard coded, and guaranteed to have first
and last names separated by a space. So how can the same code with the
same input produce a runtime error, then on the next run process as
expected?

On Tue, 18 May 2010 00:52:31 +0900, Branden T.
[email protected] wrote:

end
recipient_array = Array.new(santa_array)
else
puts “santa_array.count == #{santa_array.count}”
darth vader, recipient == han solo
anakin skywalker, recipient == jeanluc piccard
… so on and so forth, continuing to print properly…

As you can see from the above output, I ran my code twice, with no
modifications, all names are hard coded, and guaranteed to have first
and last names separated by a space. So how can the same code with the
same input produce a runtime error, then on the next run process as
expected?

You don’t check that index < recipient_array.size so if enough last
names
match recipient_array[index] will be out of bounds. In Ruby Array.[]
returns nil for out of bounds indices. To answer your exact question the
random order given by shuffle! will be different each time you run the
program so although the input is the same the result of your algorithm
is
not.

And here’s some sample output:
brandentanga$ ./secretSanta.rb
./secretSanta.rb:67:in block in <main>': undefined methodlast’ for
nil:NilClass (NoMethodError)

bug maybe? try trunk and see if it does the same…
-rp

Alex G. wrote:

You don’t check that index < recipient_array.size so if enough last
names
match recipient_array[index] will be out of bounds. In Ruby Array.[]
returns nil for out of bounds indices. To answer your exact question the
random order given by shuffle! will be different each time you run the
program so although the input is the same the result of your algorithm
is
not.

Aaaah, that makes perfect sense. Thanks for the help.