Reputation: 142
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
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
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