Ruby: ¿Puedo escribir cadenas multilíneas sin concatenación?


¿Hay alguna manera de hacer que esto se vea un poco mejor?

conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7 ' +
          'from table1, table2, table3, etc, etc, etc, etc, etc, ' +
          'where etc etc etc etc etc etc etc etc etc etc etc etc etc'

Como, ¿hay una manera de implicar concatenación?

Author: derobert, 2010-02-25

13 answers

Hay partes de esta respuesta que me ayudaron a obtener lo que necesitaba (concatenación de múltiples líneas SIN espacios en blanco adicionales), pero como ninguna de las respuestas reales lo tenía, las estoy compilando aquí:

str = 'this is a multi-line string'\
  ' using implicit concatenation'\
  ' to prevent spare \n\'s'

=> "this is a multi-line string using implicit concatenation to eliminate spare
\\n's"

Como bono, aquí hay una versión que usa la sintaxis divertida de HEREDOC (a través de este enlace):

p <<END_SQL.gsub(/\s+/, " ").strip
SELECT * FROM     users
         ORDER BY users.id DESC
END_SQL
# >> "SELECT * FROM users ORDER BY users.id DESC"

Este último sería principalmente para situaciones que requieren más flexibilidad en el procesamiento. Personalmente no me gusta, pone el procesamiento en un lugar extraño w. r. t. la cadena (es decir, delante de él, pero usando métodos de instancia que generalmente vienen después), pero está ahí. Tenga en cuenta que si está sangrando el último identificador END_SQL (que es común, ya que probablemente esté dentro de una función o módulo), necesitará usar la sintaxis con guiones (es decir, p <<-END_SQL en lugar de p <<END_SQL). De lo contrario, el espacio en blanco de sangría hace que el identificador se interprete como una continuación de la cadena.

Esto no ahorra mucho escribiendo, pero se ve mejor que usar signos+, para me.

EDITAR: Añadiendo uno más:

p %{
SELECT * FROM     users
         ORDER BY users.id DESC
}.gsub(/\s+/, " ").strip
# >> "SELECT * FROM users ORDER BY users.id DESC"
 482
Author: A. Wilson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-02 19:35:03

Sí, si no te importa que se inserten nuevas líneas adicionales:

 conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7
            from table1, table2, table3, etc, etc, etc, etc, etc,
            where etc etc etc etc etc etc etc etc etc etc etc etc etc'

Alternativamente puede usar un heredoc :

conn.exec <<-eos
   select attr1, attr2, attr3, attr4, attr5, attr6, attr7
   from table1, table2, table3, etc, etc, etc, etc, etc,
   where etc etc etc etc etc etc etc etc etc etc etc etc etc
eos
 154
Author: Mark Byers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-25 09:42:29

En ruby 2.0 ahora puedes usar %

Por ejemplo:

SQL = %{
SELECT user, name
FROM users
WHERE users.id = #{var}
LIMIT #{var2}
}
 148
Author: Robbie Guilfoyle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-28 01:33:51

Hay múltiples sintaxis para cadenas de varias líneas como ya ha leído. Mi favorito es el estilo Perl:

conn.exec %q{select attr1, attr2, attr3, attr4, attr5, attr6, attr7
      from table1, table2, table3, etc, etc, etc, etc, etc,
      where etc etc etc etc etc etc etc etc etc etc etc etc etc}

La cadena multilínea comienza con %q, seguida de un {, [ o (, y luego termina con el carácter invertido correspondiente. %q no permite la interpolación; %Q lo hace para que pueda escribir cosas como esta:

conn.exec %Q{select attr1, attr2, attr3, attr4, attr5, attr6, attr7
      from #{table_names},
      where etc etc etc etc etc etc etc etc etc etc etc etc etc}

En realidad no tengo idea de cómo se llaman estos tipos de cadenas multilíneas, así que llamémoslas multilíneas Perl.

Tenga en cuenta, sin embargo, que si si usas Perl multilines o heredocs como Mark y Peter han sugerido, terminarás con espacios en blanco potencialmente innecesarios. Tanto en mis ejemplos como en sus ejemplos, las líneas "from" y "where" contienen espacios en blanco iniciales debido a su sangría en el código. Si no desea este espacio en blanco, debe usar cadenas concatenadas como lo está haciendo ahora.

 51
Author: Hongli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-26 09:13:42

A veces vale la pena eliminar nuevos caracteres de línea \n como:

conn.exec <<-eos.squish
 select attr1, attr2, attr3, attr4, attr5, attr6, attr7
 from table1, table2, table3, etc, etc, etc, etc, etc,
 where etc etc etc etc etc etc etc etc etc etc etc etc etc
eos
 27
Author: Kamil Lelonek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-16 06:57:19
conn.exec = <<eos
  select attr1, attr2, attr3, attr4, attr5, attr6, attr7
  from table1, table2, table3, etc, etc, etc, etc, etc,
  where etc etc etc etc etc etc etc etc etc etc etc etc etc
eos
 15
Author: Peter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-25 20:51:13

También puede usar tres comillas dobles

x = """
this is 
a multiline
string
"""

2.3.3 :012 > x
 => "\nthis is\na multiline\nstring\n"

Si es necesario eliminar los saltos de línea "\n" use la barra invertida "\" al final de cada línea

 14
Author: juliangonzalez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-20 23:48:05

Otras opciones:

#multi line string
multiline_string = <<EOM
This is a very long string
that contains interpolation
like #{4 + 5} \n\n
EOM

puts multiline_string

#another option for multiline string
message = <<-EOF
asdfasdfsador #{2+2} this month.
asdfadsfasdfadsfad.
EOF

puts message
 9
Author: Alex Cohen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-28 19:03:29
conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7 ' <<
        'from table1, table2, table3, etc, etc, etc, etc, etc, ' <<
        'where etc etc etc etc etc etc etc etc etc etc etc etc etc'

 7
Author: Dom Brezinski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-25 20:52:55

Si hace mente espacios adicionales y nuevas líneas, puede utilizar

conn.exec %w{select attr1, attr2, attr3, attr4, attr5, attr6, attr7
  from table1, table2, table3, etc, etc, etc, etc, etc,
  where etc etc etc etc etc etc etc etc etc etc etc etc etc} * ' '

(use %W para cadenas interpoladas)

 5
Author: UncleGene,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-12 22:09:53

Recientemente con las nuevas características de Ruby 2.3, el nuevo squiggly HEREDOC le permitirá escribir nuestras cadenas multilínea de una manera agradable con un cambio mínimo, por lo que usar esto combinado con el .squish le permitirá escribir multilínea de una manera agradable!

[1] pry(main)> <<~SQL.squish
[1] pry(main)*   select attr1, attr2, attr3, attr4, attr5, attr6, attr7
[1] pry(main)*   from table1, table2, table3, etc, etc, etc, etc, etc,
[1] pry(main)*   where etc etc etc etc etc etc etc etc etc etc etc etc etc
[1] pry(main)* SQL
=> "select attr1, attr2, attr3, attr4, attr5, attr6, attr7 from table1, table2, table3, etc, etc, etc, etc, etc, where etc etc etc etc etc etc etc etc etc etc etc etc etc"

Ref: https://infinum.co/the-capsized-eight/multiline-strings-ruby-2-3-0-the-squiggly-heredoc

 5
Author: Mark Jad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-01 11:42:08
conn.exec [
  "select attr1, attr2, attr3, ...",
  "from table1, table2, table3, ...",
  "where ..."
].join(' ')

Esta sugerencia tiene la ventaja aquí-documentos y cadenas largas que los indentadores automáticos pueden sangrar cada parte de la cadena apropiadamente. Pero tiene un costo de eficiencia.

 3
Author: Aidan Cully,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-25 21:10:16

Para evitar cerrar los paréntesis para cada línea, simplemente puede usar comillas dobles con una barra invertida para escapar de la nueva línea:

"select attr1, attr2, attr3, attr4, attr5, attr6, attr7 \
from table1, table2, table3, etc, etc, etc, etc, etc, \
where etc etc etc etc etc etc etc etc etc etc etc etc etc"
 2
Author: Pwnrar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-15 16:34:36