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
-_-