Learning ruby part 6 using blocks and yield

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


1 Comment
  • Bruno
    Posted at 01:35h, 23 July

    ¿Por qué copias el código de codeschool?
    Con los mismos textos y explicaciones
    -_-

Post A Comment