Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rubocop rule: Never use 'do' with multi-line 'while

I have the following code

  # colours a random cell with a correct colour
  def colour_random!
    while true do
      col, row = rand(columns), rand(rows)
      cell = self[row,col]
      if cell.empty? then
        cell.should_be_filled? ? cell.colour!(1) : cell.colour!(0)
        break
      end
    end
  end

it's not that important what's doing, although it should pretty obvious. The point is that Rubocop gives me a warning

Never use 'do' with multi-line 'while

Why should I not do that? How should I do it then?

like image 365
Ondrej Janacek Avatar asked Jan 22 '14 17:01

Ondrej Janacek


2 Answers

while is a keyword,so you don't need to pass a block. Without do..end it will work fine. The below is fine

  def colour_random!
    while true
      col, row = rand(columns), rand(rows)
      cell = self[row,col]
      if cell.empty? then
        cell.should_be_filled? ? cell.colour!(1) : cell.colour!(0)
        break
      end
    end
  end

while is a keyword, and if you pass a block to it, like do..end, it still works as you asked it to do, by not throwing any error, rather just a warning. But it could be dangerous if you try to pass a Proc or Method object to it, and dynamically try to convert it to a block using & keyword, as we do generally. That means

# below code will work as expected just throwing an warning.
x = 2
while x < 2 do
  #code
end

But if you try to do by mistake like below

while &block # booom!! error

The reason is while is a keyword, which don't support any to_proc method to satisfy your need. So it can be dangerous.

Ruby style guide also suggested that Never use while/until condition do for multi-line while/until

I think the reason is as Nobuyoshi Nakada said in the mailing list

loop is a kernel method which takes a block. A block introduces new local variable scope.

  loop do
    a = 1
    break   
  end   
  p a #=> causes NameError

while doesn't.

  while 1
    a = 1
    break   
  end
  p a #=> 1
like image 51
Arup Rakshit Avatar answered Oct 18 '22 06:10

Arup Rakshit


Ruby actually has a shortcut for while true: the loop statement.

def colour_random!
  loop do
    col, row = rand(columns), rand(rows)
    cell = self[row,col]
    if cell.empty? then
      cell.should_be_filled? ? cell.colour!(1) : cell.colour!(0)
      break
    end
  end
end
like image 30
Patrick Oscity Avatar answered Oct 18 '22 07:10

Patrick Oscity