¿Hay un ciclo “do … while” en Ruby?

Estoy usando este código para permitir que el usuario ingrese nombres mientras el progtwig los almacena en una matriz hasta que ingresen una cadena vacía (deben presionar Enter después de cada nombre):

people = [] info = 'a' # must fill variable with something, otherwise loop won't execute while not info.empty? info = gets.chomp people += [Person.new(info)] if not info.empty? end 

Este código se vería mucho mejor en un ciclo do … while:

 people = [] do info = gets.chomp people += [Person.new(info)] if not info.empty? while not info.empty? 

En este código, no tengo que asignar información a una cadena aleatoria.

Desafortunadamente, este tipo de bucle no parece existir en Ruby. ¿Alguien puede sugerir una mejor manera de hacer esto?

PRECAUCIÓN :

El begin end while es rechazado por Matz, el autor de Ruby. En su lugar, sugiere usar Kernel#loop , por ejemplo

 loop do # some code here break if  end 

Para obtener más detalles, consulte: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745 ( o vía Wayback ), y este wiki: http: // rosettacode. org / wiki / Loops / Do-while # Ruby

Encontré el siguiente fragmento mientras leía el origen de Tempfile#initialize en la biblioteca principal de Ruby:

 begin tmpname = File.join(tmpdir, make_tmpname(basename, n)) lock = tmpname + '.lock' n += 1 end while @@cleanlist.include?(tmpname) or File.exist?(lock) or File.exist?(tmpname) 

A primera vista, supuse que el modificador while se evaluaría antes del contenido de begin … end, pero ese no es el caso. Observar:

 >> begin ?> puts "do {} while ()" >> end while false do {} while () => nil 

Como era de esperar, el ciclo continuará ejecutándose mientras el modificador sea verdadero.

 >> n = 3 => 3 >> begin ?> puts n >> n -= 1 >> end while n > 0 3 2 1 => nil 

Si bien me alegraría nunca volver a ver este idioma, comience … el final es bastante poderoso. El siguiente es un modismo común para memorizar un método de una línea sin params:

 def expensive @expensive ||= 2 + 2 end 

Esta es una forma fea pero rápida de memorizar algo más complejo:

 def expensive @expensive ||= begin n = 99 buf = "" begin buf < < "#{n} bottles of beer on the wall\n" # ... n -= 1 end while n > 0 buf < < "no more bottles of beer" end end 

Escrito originalmente por Jeremy Voorhis . El contenido se ha copiado aquí porque parece haberse eliminado del sitio de origen. Las copias también se pueden encontrar en el Archivo web y en Ruby Buzz Forum . -Bill el lagarto

Me gusta esto:

 people = [] begin info = gets.chomp people += [Person.new(info)] if not info.empty? end while not info.empty? 

Referencia: Ruby’s Hidden do {} while () Loop

¿Qué tal esto?

 people = [] until (info = gets.chomp).empty? people += [Person.new(info)] end 

Aquí está el artículo completo del enlace muerto del hubbardr a mi blog.

Encontré el siguiente fragmento mientras leía el origen de Tempfile#initialize en la biblioteca principal de Ruby:

 begin tmpname = File.join(tmpdir, make_tmpname(basename, n)) lock = tmpname + '.lock' n += 1 end while @@cleanlist.include?(tmpname) or File.exist?(lock) or File.exist?(tmpname) 

A primera vista, supuse que el modificador while se evaluaría antes del contenido de begin...end , pero ese no es el caso. Observar:

 >> begin ?> puts "do {} while ()" >> end while false do {} while () => nil 

Como era de esperar, el ciclo continuará ejecutándose mientras el modificador sea verdadero.

 >> n = 3 => 3 >> begin ?> puts n >> n -= 1 >> end while n > 0 3 2 1 => nil 

Si bien me alegraría nunca volver a ver este idioma, begin...end es bastante poderoso. El siguiente es un modismo común para memorizar un método de una línea sin params:

 def expensive @expensive ||= 2 + 2 end 

Esta es una forma fea pero rápida de memorizar algo más complejo:

 def expensive @expensive ||= begin n = 99 buf = "" begin buf < < "#{n} bottles of beer on the wall\n" # ... n -= 1 end while n > 0 buf < < "no more bottles of beer" end end 

Esto funciona correctamente ahora:

 begin # statment end until  

Pero, puede eliminarse en el futuro, porque la statement de begin es contraintuitiva. Ver: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745

Matz recomienda hacerlo de esta manera:

 loop do # ... break if  end 

Por lo que veo, a Matz no le gusta la construcción

 begin  end while  

porque, es semántica es diferente de

  while  

en que la primera construcción ejecuta el código primero antes de verificar la condición, y la segunda construcción prueba la condición primero antes de ejecutar el código (si es que lo hace). Supongo que Matz prefiere mantener el segundo constructo porque coincide con un constructo de línea de enunciados if.

Nunca me gustó el segundo constructo incluso para las declaraciones if. En todos los demás casos, la computadora ejecuta el código de izquierda a derecha (por ejemplo, || y &&) arriba a abajo. Los humanos leen el código de izquierda a derecha de arriba a abajo.

Sugiero los siguientes constructos en su lugar:

 if  then  # matches case-when-then statement while  then   while  begin  end while  # or something similar but left-to-right 

No sé si esas sugerencias se analizarán con el rest del lenguaje. Pero, en cualquier caso, prefiero mantener la ejecución de izquierda a derecha y la consistencia del lenguaje.

 a = 1 while true puts a a += 1 break if a > 10 end 

Aqui hay otro más:

 people = [] 1.times do info = gets.chomp unless info.empty? people += [Person.new(info)] redo end end 
 ppl = [] while (input=gets.chomp) if !input.empty? ppl < < input else p ppl; puts "Goodbye"; break end end