Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialUlfar Ellenarson
5,277 PointsWhy 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
Greg Yardley
4,236 PointsIn 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
5,277 PointsSo 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.