Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Ruby Ruby Modules Ruby Core Modules Enumerable

Ulfar Ellenarson
Ulfar Ellenarson
5,277 Points

Why create the method each in the class Game?

I noticed during the creation of the method each that Jason includes the players.each (&block) and it made me wonder why he is creating the each method as it is already included in the array players. This had already been defined prior when he creates the score method. See code below class Game include Enumerable

attr_accessor :players

def each(&block) players.each(&block) end

def initialize @players = [] end

def add_player(player) players.push(player) end

def score score = 0 players.each do |player| score += player.score end score end end

Notice that each is already defined in the method def score. I know he mentions that the enumerable mixing needs the each method as defined in the Enumerable documentation. "The class must provide a method each, which yields successive members of the collection." But to me it seems that the class Game already is using the each method in the method score so why does it need to be defined?

Please help me understand and the use of examples would be really helpful.

2 Answers

In the score method of the Game class, the code does call an 'each' method -- but that doesn't imply the Game class has an 'each' method. The actual code there is 'players.each'. Methods belong to classes, and 'players' isn't a Game - it's actually an Array, which got set up by this code:

attr_accessor :players

def initialize
  @players = []
end

Try leaving the 'each' method out of the Game class, like so:

class Game
  include Enumerable

  attr_accessor :players

  def initialize 
    @players = [] 
  end

  def add_player(player) 
    players.push(player) 
  end

  def score 
    score = 0 
    players.each do |player| 
      score += player.score 
    end 
    score 
  end 
end

Now go into the irb console and try using some of the methods you get as part of the Enumerable mixin - they're all listed at http://ruby-doc.org/core-2.2.4/Enumerable.html. For example, you could do this:

game = Game.new
game.count    # the count method is part of the Enumerable mixin

You'll get something like this error:

NoMethodError: undefined method `each' for #<Game:0x007fe49c85dbe8>

That's because the count method from the Enumerable mixin tried to call 'each' on the 'game' object, and it's not there. The method 'game.players.each' is there, but that's not what the Enumerable mixin is looking for. That's why this code has to be added:

def each(&block) 
  players.each(&block) 
end

All the Game class is really saying is "Hey, I need an each method to use the Enumerable mixin! Where can I get one of those? Oh, my 'players' instance variable is an Array, so it has an each method - whenever a method from the Enumerable mixin asks me for my each method, I'm just going to use the each method from my 'players' variable." Now if you type 'game = Game.new' and then 'game.count' in irb, you won't get an error.

Does that help?

Ulfar Ellenarson
Ulfar Ellenarson
5,277 Points

So if I understand correctly then Jason is creating an each method by using the each method from the array players. Would it not also be possible to do def each(&block) yield end

But I understand that the mixing Enumerable needs an each method and that we are using the each method from the Array class. It just seems redundant that Enumerable does not include it.

For example the line: puts game1.any?{|player| player.score > 80} is using the each method on the block {|player| player.score > 80} as the instance method .any? is from the enumerable mixin.