Let's build a Library class that will manage our growing collection of games. We've already written a list
method that prints the names of all our games, but it uses an ugly for
loop to iterate the list. Refactor it to use each
with a block instead.less
#seed.rb GAMES = [ Game.new('Contra', year: 1987, system: 'NES'), Game.new('Civilization', year: 1991, system: 'PC'), Game.new('The Legend of Zelda', year: 1986, system: 'NES'), Game.new('Mega Man X2', year: 1995, system: 'SNES'), Game.new('Super Metroid', year: 1994, system: 'SNES'), Game.new('Sim City 2000', year: 1993, system: 'PC'), Game.new('Starcraft', year: 1998, system: 'PC') ]
#game.rb 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 end
class Library attr_accessor :games def initialize(games = []) self.games = games end def list for i in 0...(games.length) game = games[i] puts game.name end end end
Answer:oop
class Library attr_accessor :games def initialize(games = []) self.games = games end def list games.each do |game| puts game.name end end end
We'd like to be able to operate on our games by system. Implement an each_on_system
method that iterates over our games
using each
and yields to a block for every game on the requested system. To test that it's working, we'll call each_on_system
with a simple block that prints a message for every Super Nintendo game in our library. See the example.rb
below.flex
library = Library.new(GAMES) library.each_on_system("SNES") { puts "Found a Super Nintendo game" }
Answer:ui
class Library attr_accessor :games def initialize(games = []) self.games = games end def each_on_system(system) self.games.each do |game| yield if game.system == system end end end
Our each_on_system
method is working, but it's not very useful unless the block has access to each game that we find. Modify each_on_system
to pass the Game object into the block so we can print its name.spa
class Library attr_accessor :games def initialize(games = []) self.games = games end def each_on_system(system) games.each { |game| yield game if game.system == system} end end
Earlier we wrote a list
method that prints the name of each game in our library. We can make the output formatting more flexible by allowing a block to be passed to the list
method. We'll yield each game to the block and allow the block to format and return a string for us to display. Modify the list
method to yield to a block and print whatever the block returns.code
library = Library.new(GAMES) library.list { |game| "#{game.name} (#{game.system}) - #{game.year}" }
Answer:orm
class Library attr_accessor :games def initialize(games = []) self.games = games end def list games.each do |game| puts yield game end end end
Let's add the power of Ruby's Enumerable module to our game library. Implement an each
method that yields each game in the library. Finally, include the Enumerable module so that we'll be able to call methods like select
and collect
on our library.blog
library = Library.new(GAMES) library.select { |game| game.year == 1986 } library.collect { |game| game.system }
Answer:string
class Library include Enumerable attr_accessor :games def initialize(games = []) self.games = games end def each self.games.each {|game| yield game} end end
Now that our library is complete, let's play some games! A friend has given us his Emulator
class to use, and we've implemented methods to play a game and grab a screenshot. But look at all that duplicated code in play
and screenshot
. Refactor the duplication (the begin
, new
and rescue
parts) into a private method called emulate
that handles the emulator setup and exception handling and yields the emulator instance to a block.it
class Emulator def initialize(system) # Creates an emulator for the given system end def play(game) # Runs the given game in the emulator end def start(game) # Loads the given game but doesn't run it end def screenshot # Returns a screenshot of the currently loaded game end end
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 play begin emulator = Emulator.new(system) emulator.play(self) rescue Exception => e puts "Emulator failed: #{e}" end end def screenshot begin emulator = Emulator.new(system) emulator.start(self) emulator.screenshot rescue Exception => e puts "Emulator failed: #{e}" end end end
Answer:
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 play emulate do |emulator| emulator.play(self) end end def screenshot emulate do |emulator| emulator.start(self) emulator.screenshot end end private def emulate emulator = Emulator.new(system) yield emulator rescue Exception => e puts "Emulator failed: #{e}" end end