2

I'm working with a Ruby project for school, and have sadly not been able to find an answer to this question in my literature.

I have an array of camping lots, each containing a guest. I initialize the lots like this:

lots = Array.new

for i in (1..36)
  lots[i] = Lot.new(i)
end

Further down I create a Guest object, initialize it, and now I want to add the Guest to my Lot. The method in the class Lot looks like this:

def AddGuest(guest)
  @guest = guest
end

The problem comes when I want to call the method, as the Lot is in an Array.

lots[lotnumber].AddGuest(guest)

This call gives me the error:

undefined method `+@' for #<Guest:0x2c1ff14> (NoMethodError)

I have used require, so the classes know about each other. I've had quite a hard time understanding Ruby, could my error be that I try to access the AddGuest method in the Array class? I'm used to doing things like this in C++.

Below is the full source (the relevant parts at least).

Entire Lot class:

class Lot

  def initialize(number)
    @gauge = rand(2000) + 2000
    @number = number
    @guest = false
  end

  def Occupied()
    return @guest
  end

  def AddGuest(guest)
    @guest = guest
  end

  def RemoveGuest()
    @guest = false
  end

end

Parts of main.rb

#includes
require 'guest'
require 'lot'

#initiate comparison variables
userInput = "0"
numberOfGuests = 0
foundLot = false
guests = Array.new
lots = Array.new

#initialize lot list
for i in (1..36)
  lots[i] = Lot.new(i)
end

Player input omitted

#make sure lot is not taken
while foundLot == false do
  lotnumber = rand(35)+1
  if lots[lotnumber].Occupied() == false then
    foundLot = "true"
  end
end
foundLot = false

guest = Guest.new(firstName, lastName, adress, phone, arrival, lotnumber)
guests.insert(numberOfGuests, guest)
numberOfGuests++

lots[lotnumber].AddGuest(guest) #this is where error hits

end

end

end
3
  • 5
    Can you post the full source? is the AddGuest method defined in the scope of a class? Commented Jul 13, 2009 at 20:25
  • Is it possible that you accidentally put AddGuest under private or protected? Commented Jul 13, 2009 at 20:46
  • Just FYI, you can create the lots more succinctly as lots = (1..36).collect {|n| Lot.new n}. Ruby eliminates a lot of explicit looping. Commented Jul 13, 2009 at 21:50

3 Answers 3

6

The error appears to be related to your use of the ++ operator, which is, quite naturally, supported in C++, but is not supported in Ruby.

The equivalent is:

numberOfGuests += 1
Sign up to request clarification or add additional context in comments.

1 Comment

That solved it! Thanks everybody for the great quick answers. Now if i could just stop adding semicolons to the end of my lines... :)
1

A couple little tips...

[1]

A slightly more idiomatic way to write this...

for i in (1..36)
  lots[i] = Lot.new(i)
end

would be...

(1..36).each { |i| lots[i] << Lot.new(i) }

[2]

To remove a Guest from a Lot, you might want to set it to nil rather than false. This would be my suggestion...

class Lot

  def initialize(number)
    @gauge = rand(2000) + 2000
    @number = number
    # Don't need to set @guest -- it's nil by default.
  end

  # In Ruby, methods that return a boolean often have a "?".
  # Makes it "read better" when you call the method. (See
  # usage sample.)
  def occupied?
    ! @guest.nil?
  end

  # There's a more commonplace way to do this. See below...
  def add_guest(guest)
    @guest = guest
  end

  def remove_guest()
    @guest = nil
  end

end

Example of usage:

>> lot = Lot.new(2)
=> #<Lot:0x1300920 @number=2, @gauge=3444>
>> lot.occupied
=> false
>> lot.add_guest('A guest')
=> "A guest"
>> lot.occupied?
=> true
>> lot.remove_guest
=> nil
>> lot.occupied?
=> false

Take two...

It's conventional to use attr_accessor methods in your class definition. They automatically add getter and setter methods to your class. You could do that instead of add_guest and remove_guest if you wanted to follow the common Ruby pattern...

class Lot

  attr_accessor :number, :gauge, :guest

  def initialize(number)
    @gauge = rand(2000) + 2000
    @number = number
  end

  def occupied?
    ! @guest.nil?
  end

end

Usage...

irb(main):017:0> lot = Lot.new(3)
=> #<Lot:0xb7f7fca8 @gauge=3186, @number=3>

Set the Guest of a Lot (like add_guest)...

irb(main):019:0> lot.guest = 'A guest'
=> "A guest"
irb(main):020:0> lot.occupied?
=> true

Get the Guest for a Lot...

irb(main):025:0> lot.guest
=> "A guest"

Remove the Guest...

irb(main):021:0> lot.guest = nil
=> nil
irb(main):023:0> lot.occupied?
=> false

4 Comments

Actually, even better is to use Array#collect to do the dirty work for you. (1..36).collect { |i| Lot.new(i) } though this will be 0-indexed, not 1-indexed as in the example.
Or Array.new(36) { |i| Lot.new(i) }
Don't you want "=", not "<<", in "lots[i] << Lot.new(i)"?
"# Don't need to set @guest -- it's nil by default." - if you use warnings, then using an uninitialized @guest will generate a warning. Your mileage may vary.
0

Generally Ruby method names are not capitalized. The convention are simply: ClassName, CONSTANT, method_name.

Since you have an Array of Lot objects, the following should be true:

lots.class # => Array
lots[1].class # => Lot

The method called should be defined for Lot.

2 Comments

Sorry if i was unclear, the method called is defined for Lot. When i was talking about the Array class i meant the built-in one, i have not written my own.
I just posted a different response that addresses the code sample you pasted. I hope that helps.

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.