Gian Franco Fioriello
Gian Franco Fioriello

Reputation: 142

How to use &block in Ruby

I'm trying to use blocks in Ruby, I have this code:

  def positions
    return horizontally_position if orientation == "horizontally"
    vertically_position
  end

  def horizontally_position
    res = []
    for x in position[0]..end_coord(0) 
      res << [x, position[1]]
    end
    return res
  end

  def vertically_position
    res = []
    for y in position[1]..end_coord(1)
      res << [position[0], y]
    end
    return res
  end

There seems to be repeated code , and want to use a block or to a yield improve performance , but do not know how!

Do this :

  def positions
    return h_v_position(0, {[x, position[1]]}) if orientation == "horizontally"
    h_v_position(1, {[position[0], y]})
  end

  def h_v_positions(coord, &block) 
    res = []
    for x in position[coord]..end_coord(coord) 
      res << block.call
    end
    return res
  end

But isn't work.. there is any help?

Upvotes: 1

Views: 658

Answers (2)

Gian Franco Fioriello
Gian Franco Fioriello

Reputation: 142

After think and searched in google I found the best way to do this, and understood how to use &blocks and yields in Ruby.

In the bigining, my problem was this repeted code:

  def horizontally_position
    res = []
    for x in position[0]..end_coord(0) 
      res << [x, position[1]]
    end
    return res
  end

  def vertically_position
    res = []
    for y in position[1]..end_coord(1)
      res << [position[0], y]
    end
    return res
  end

The first thing I do to aboid the repeated code was use a yield:

  def position_by(coord) # ²
    res = []
    for n in position[coord]..end_coord(coord) 
      res <<  yield(n) # ³
    end
    return res
  end  

  def horizontally_position # ¹
    position_by(0) { |n| [n, position[1]] } # ⁴
  end

  def vertically_position # ¹
    position_by(1) { |n| [position[0], n] } # ⁴
  end

¹ When this method will called, it will call to position_by(1) or position_by(0).
² This method will start to execute and when it comes to << yield(n)...
³ It will come again to vertically_position" or horizontally_position and will replace the yield in position_by for the code in brackets in horizontally_position (or vertically_position). Sorry for the redundancy.

After do that I saw the method position_by(coord) and wish to refactor it a little.

First refactor, using yield:

  def position_by(end_coor)
    position[end_coor]..end_coord(end_coor).map do |x|    
        yield x
    end
  end

Then use a &block:

  def position_by(coord, &block) # ⁵
        (position[coord]..end_coord(coord)).map &block
  end 

⁵ Here we are mapping each position to a & block , and a block can be [ x , position ( 1) ] or [position ( 0 ) , y] , Where x or and will be replace for the position [ coord ] corresponding.

Upvotes: 0

Patrick Oscity
Patrick Oscity

Reputation: 54684

If you need to handle block arguments you can either use implicit yield:

def foo
  yield
end

or you can pass the block explicitly and call it with block.call:

def foo(&block)
  block.call
end

So if you replace res << &block with res << block.call the block should be called properly.

Upvotes: 2

Related Questions