1

From codeschool's ruby-bits course, I am trying to understand how these classes work- I have a Game class and a collection class called Library that stores a collection of games.

class Game
  attr_accessor :name, :year, :system
  attr_reader :created_at

  def initialize(name, options={})
    self.name = name
    self.year = options[:year]
    self.system = options[:system]
    @created_at = Time.now
  end


  def ==(game)
    name == game.name && 
    system == game.system &&
    year == game.year
  end
end

Library class:

class Library
  attr_accessor :games

  def initialize(*games)
    self.games = games
  end

  def has_game?(*games)
    for game in self.games
      return true if game == game
    end
    false
  end
end

Now I create some games:

contra = Game.new('Contra', {
  year: 1994,
  system: 'nintendo'
})

mario = Game.new('Mario', {
  year: 1996,
  system: 'SNES'
})

sonic = Game.new('Sonic', {
  year: 1993,
  system: 'SEGA'
})

and instantiate a new collection:

myCollection = Library.new(mario, sonic)

When I try to find if a certain game is in myCollection using the has_game? method, I always get true

puts myCollection.has_game?(contra) #=> returns **true** even though this has never been inserted as part of the collection.

What am I doing wrong?

Amit Erandole
  • 11,336
  • 20
  • 64
  • 98

2 Answers2

2
return true if game == game

I think this statement may cause problem.

It is always true.

You may want something like this:

def has_game?(wanted)
  for game in self.games
    return true if game == wanted
  end
  false
end
Amit Erandole
  • 11,336
  • 20
  • 64
  • 98
Salih Erikci
  • 4,976
  • 11
  • 36
  • 68
1

There are a couple things that are wrong here:

  1. Instead of using self.XXXX to create instance variables you should use @XXXX, it accesses the values directly, using self actually performs another method call, refer here for more details: Instance variable: self vs @

  2. As the others mentioned game == game will always return true, the answer that was already posted doesn't allow for passing more than a single game to has_game?

Here are my changes that work correctly:

class Game
  attr_accessor :name, :year, :system
  attr_reader :created_at

  def initialize(name, options={})
    @name       = name
    @year       = options[:year]
    @system     = options[:system]
    @created_at = Time.now
  end


  def ==(game)
    @name == game.name && 
    @system == game.system &&
    @year == game.year
  end
end

class Library
  attr_accessor :games

  def initialize(*games)
    @games = games
  end

  # only returns true if this Library
  # has ALL of the games passed to has_game? 
  def has_game?(*_games)
    _games.each do |game|
      return false if not @games.include?(game)
    end

    return true
  end
end

contra = Game.new('Contra', {
  year: 1994,
  system: 'nintendo'
})

mario = Game.new('Mario', {
  year: 1996,
  system: 'SNES'
})

sonic = Game.new('Sonic', {
  year: 1993,
  system: 'SEGA'
})

myCollection = Library.new(mario, sonic)
puts "Collection has Contra? #{myCollection.has_game?(contra)}"
puts "Collection has Sonic and Mario #{myCollection.has_game?(sonic, mario)}"

output:

Collection has Contra? false
Collection has Sonic and Mario true
Community
  • 1
  • 1
Hunter McMillen
  • 56,682
  • 21
  • 115
  • 164