23 Sep Learning ruby part 6 using blocks and yield
Differents ways to use blocks
block = ["heriberto", "claudia cecilia", "martinez", "perez magana"]
block.each {|value| puts value} #or puts "=======================================\n" block.each do |value| puts value end puts "=======================================\n" backward_words = block.map {|word| word} puts backward_words puts "=======================================\n" block.map do |value| puts value end
Using Yield
def call_this_method_twice yield yield end call_this_method_twice {puts "print method"}
Now we use yield with arguments
def call_method yield "tweet" end call_method {|myarg| puts myarg} #print tweet call_method {|myarg| puts myarg.upcase} #this will print TWEET
Yield with return value
def call_method puts yield end call_method {“heriberto perez”} #will print heriberto perez
Combining yield arguments with return value
def call_method_combine argument_backword = yield "myownword" puts argument_backword end call_method_combine{|arg| puts arg.reverse}
Using blocks
class Timeline def list_tweets @user.friends.each do |friend| friend.tweets.each {|tweet|puts tweet} end end def store_tweets @user.friends.each do |friend| friend.tweets.each {|tweet| tweet.cache} end end end #or we can to refactor the before code class Timeline def each @user.friends.each do |friend| friend.tweets.each {|tweet| yield tweet} end end end timeline = Timeline.new(user) timeline.each {|tweet| puts tweet} timeline.each {|tweet| tweet.cache}
Other example
def while_signed_in_as(user) begin sign_in(user) yield rescue ConnectionError => e logger.error(e) ensure sign_out(user) end end while_signed_in_as(user) do post(tweet) end while_signed_in_as(user) do retrieve_list(list_id) end
Some Exercises (Taken from codeschool.com)
Iterating with Blocks
Let’s build a Library class that will manage our growing collection of games. We’ve already written a listmethod that prints the names of all our games, but it uses an ugly for loop to iterate the list. Refactor it to useeach with a block instead.
Origin Code
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
Final code
class Library attr_accessor :games def initialize(games = []) self.games = games end def list games.each do |game| puts game.name end end end
Yielding to Blocks
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 evey Super Nintendo game in our library. See the example.rb below.
Origin code:
class Library attr_accessor :games def initialize(games = []) self.games = games end def each_on_system(system) end end
final code:
class Library attr_accessor :games def initialize(games = []) self.games = games end def each_on_system(system) games.each do |game| yield if game.system == system end end end
Passing Arguments to Blocks
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.
Origin code:
class Library attr_accessor :games def initialize(games = []) self.games = games end def each_on_system(system) games.each do |game| yield if game.system == system end end end
Final code:
class Library attr_accessor :games def initialize(games = []) self.games = games end def each_on_system(system) games.each do |game| yield game if game.system == system end end end
Returning Values from Blocks
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.
Origin code:
class Library attr_accessor :games def initialize(games = []) self.games = games end def list games.each do |game| puts game.name end end end
Final code:
class Library attr_accessor :games def initialize(games = []) self.games = games end def list games.each do |game| puts yield game end end end
Using Enumerable
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 and include the Enumerable module. That’s all we need to be able to call methods likeselect and collect on our library.
Origin code:
class Library attr_accessor :games def initialize(games = []) self.games = games end def each end end
Final code:
class Library include Enumerable attr_accessor :games def initialize(games = []) self.games = games end def each @games.each do |game| yield game end end end
Refactoring with Blocks
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 playand screenshot. Refactor the duplication (the begin, new and rescue parts) into a private method calledemulate that handles the emulator setup and exception handling and yields the emulator instance to a block.
Origin code:
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
Final Code
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.play(self) end end def screenshot emulate do @emulator.start(self) @emulator.screenshot end end private def emulate begin @emulator = Emulator.new(system) yield @emulator rescue Exception => e puts "Emulator failed: #{e}" end end end
Bruno
Posted at 01:35h, 23 July¿Por qué copias el código de codeschool?
Con los mismos textos y explicaciones
-_-