Romper cadenas largas en varias líneas en Ruby sin quitar nuevas líneas

221

Recientemente decidimos en mi trabajo una guía de estilo rubí. Uno de los edictos es que ninguna línea debe tener más de 80 caracteres. Dado que este es un proyecto de Rails, a menudo tenemos cadenas que son un poco más largas, es decir, "El usuario X quería enviarte un mensaje sobre Cosa Y " que no siempre se ajusta al límite de estilo de 80 caracteres.

Entiendo que hay tres formas de hacer que una cadena larga abarque varias líneas:

  • HEREDOC
  • % Q {}
  • Concatenación de cadenas real.

Sin embargo, todos estos casos terminan tomando más ciclos de cálculo, lo que parece una tontería. La concatenación de cadenas obviamente, pero para HEREDOCy %Qtengo que quitar las nuevas líneas, a través de algo así .gsub(/\n$/, '').

¿Existe una forma de sintaxis pura para hacer esto, que es equivalente a tener toda la cadena en una línea? El objetivo es, obviamente, no gastar ningún ciclo adicional solo porque quiero que mi código sea un poco más legible. (Sí, me doy cuenta de que tienes que hacer mucho eso ... pero para la longitud de la cuerda, esto parece una tontería).

Actualización: las barras invertidas no son exactamente lo que quiero porque pierdes la sangría, lo que realmente afecta el estilo / legibilidad.

Ejemplo:

if foo
  string = "this is a \  
string that spans lines"  
end

Encuentro lo anterior un poco difícil de leer.

EDITAR : agregué una respuesta a continuación; tres años después ahora tenemos el heredoc ondulado.

chug2k
fuente
Puede valer la pena descifrar esas cadenas.
Cheezmeister
👎🏼 No está claro si desea mantener \ncaracteres de nueva línea o no. La respuesta principal no los mantiene, pero su respuesta sí. La pregunta dice "sin quitar nuevas líneas", pero la descripción dice "[...] tengo que quitar las nuevas líneas".
Bryan Dimas

Respuestas:

432

Tal vez esto es lo que estás buscando?

string = "line #1"\
         "line #2"\
         "line #3"

p string # => "line #1line #2line #3"
Jessehz
fuente
44
eh Sí, eso es bastante perfecto. ¿Es eso realmente hacer una concatenación debajo del capó? (¿ocultar un +?)
chug2k
13
Estoy bastante seguro de que no lo es; Intenté tanto la indefinición como la redefinición de String # + y no parece que se envíe nada allí.
Jessehz
Además, poner las cadenas una al lado de la otra en la misma línea también funciona, pero eso no es muy útil.
Jessehz
3
También me gusta la solución de Emily. Pero por alguna razón me siento más cómodo con este porque los espacios en blanco iniciales en las siguientes líneas pueden sangrarse sin tener que adivinarse.
Amin Ariana
55
Re concatenación, mira la respuesta de Amadan a esta pregunta relacionada . Utiliza el código de bytes para demostrar que no está concatenando cadenas, sino que las trata como una larga.
Tom Hundt
55

Puede usar \para indicar que cualquier línea de Ruby continúa en la siguiente línea. Esto también funciona con cadenas:

string = "this is a \
string that spans lines"

puts string.inspect

saldrá "this is a string that spans lines"

Emily
fuente
11
eh Eso es bastante simple. bueno, probablemente sea demasiado pedir, pero no puedo sangrar la siguiente línea. Sería ideal si pudiera emparejarlo con el signo igual.
chug2k
55
Nota: no puede tener ningún espacio en blanco después de esa barra invertida. Debe ser el último personaje.
Julian Mann
3
Ver la respuesta de @Jessehz. La forma de tener un código bien formateado con sangría adecuada es poner cada línea entre comillas.
orden
36

Tres años después, ahora hay una solución en Ruby 2.3: el heredoc ondulado.

class Subscription
  def warning_message
    <<~HEREDOC
      Subscription expiring soon!
      Your free trial will expire in #{days_until_expiration} days.
      Please update your billing information.
    HEREDOC
  end
end

Enlace de publicación del blog: https://infinum.co/the-capsized-eight/articles/multiline-strings-ruby-2-3-0-the-squiggly-heredoc

La sangría de la línea con menos sangría se eliminará de cada línea del contenido.

chug2k
fuente
29
Para cualquiera que se pregunte: <<~HEREDOCmantiene los caracteres de nueva línea, solo elimina la sangría. Por ejemploline 1\nline 2\nline 3\n
Bryan Dimas
1
Sin embargo, la eliminación de nuevas líneas requerirá un cálculo adicional, que el tipo de OP implícito no era deseable.
henrebotha
1
@henrebotha Sí, pero OP dijo más explícitamente que quieren el "equivalente a tener toda la cadena en una línea", lo que no requeriría nuevas líneas.
Nick
Entonces, usted expresó explícitamente en su pregunta que no quería usar un heredoc y que tenía que eliminar las nuevas líneas. Su respuesta aquí utiliza un heredoc y requiere el "procesamiento posterior" que desea evitar.
lamont
17

Tuve este problema cuando trato de escribir una URL muy larga, lo siguiente funciona.

image_url = %w(
    http://minio.127.0.0.1.xip.io:9000/
    bucket29/docs/b7cfab0e-0119-452c-b262-1b78e3fccf38/
    28ed3774-b234-4de2-9a11-7d657707f79c?
    X-Amz-Algorithm=AWS4-HMAC-SHA256&
    X-Amz-Credential=ABABABABABABABABA
    %2Fus-east-1%2Fs3%2Faws4_request&
    X-Amz-Date=20170702T000940Z&
    X-Amz-Expires=3600&X-Amz-SignedHeaders=host&
    X-Amz-Signature=ABABABABABABABABABABAB
    ABABABABABABABABABABABABABABABABABABA
).join

Tenga en cuenta que no debe haber ninguna línea nueva, espacios en blanco cuando se forma la cadena de url. Si desea nuevas líneas, entonces use HEREDOC.

Aquí tiene una sangría para facilitar la lectura, facilitar la modificación, sin las comillas y las barras invertidas en cada línea. El costo de unir las cadenas debe ser insignificante.

Zack Xu
fuente
10

Modifiqué la respuesta de Zack ya que quería espacios e interpolación, pero no líneas nuevas y usé:

%W[
  It's a nice day "#{name}"
  for a walk!
].join(' ')

donde name = 'fred'esto produceIt's a nice day "fred" for a walk!

iheggie
fuente