Nivel inicial8 min de lectura · Publicado el

Interpolación de cadenas en Ruby: #{} y format

Interpolación de cadenas en Ruby: "Hola #{nombre}" con nombre = "Ana" da Hola Ana; con comillas simples sale tal cual. Comillas dobles interpolanrubentejera.com nombre = "Ana""Hola #{nombre}"Hola Anarellena el hueco'Hola #{nombre}'Hola #{nombre}sale tal cual
#{} marca el hueco de la plantilla: con comillas dobles, Ruby pone ahí el valor de nombre y escribe «Hola Ana». Con comillas simples no hay hueco, y el texto sale tal cual.

Interpolar es rellenar los huecos de una plantilla: escribes el texto fijo y marcas con #{} dónde va cada valor; Ruby rellena el hueco al ejecutar el programa.

La sintaxis: #{}

nombre = "Ana"
puts "Hola #{nombre}"   # Hola Ana

Dentro de las llaves puedes poner cualquier expresión, no solo una variable:

puts "2 + 3 = #{2 + 3}"                     # 2 + 3 = 5
puts "En mayúsculas: #{nombre.upcase}"      # En mayúsculas: ANA

Comillas dobles frente a comillas simples

Solo las comillas dobles interpolan. Con comillas simples, Ruby entiende que todo es texto literal:

nombre = "Ana"
puts "Hola #{nombre}"   # Hola Ana
puts 'Hola #{nombre}'   # Hola #{nombre}

Usa comillas simples cuando quieras justo eso: que el texto salga tal cual, sin sustituciones.

Escribir #{ sin que se interpole

Si necesitas que aparezca #{ tal cual dentro de comillas dobles, escápalo con una barra invertida:

puts "Usa \#{nombre} para interpolar"   # Usa #{nombre} para interpolar
puts 'Usa #{nombre} para interpolar'    # Usa #{nombre} para interpolar

Y un atajo que verás en código ajeno: con variables de instancia o globales, las llaves son opcionales. "Hola #@nombre" funciona igual que "Hola #{@nombre}". Con llaves se lee mejor y funciona con cualquier expresión, así que es la forma que se usa en este artículo.

@nombre = "Ana"
puts "Hola #@nombre"    # Hola Ana

Por qué interpolar en vez de concatenar con +

Con + solo puedes unir textos. Si uno de los valores es un número, Ruby se queja:

edad = 30
puts "Tengo " + edad + " años"
# TypeError: no implicit conversion of Integer into String

puts "Tengo " + edad.to_s + " años"   # funciona, pero es más largo
puts "Tengo #{edad} años"             # Tengo 30 años

La interpolación llama a to_s por ti, así que funciona con números, arrays o tus propios objetos (si definen to_s, como ves en Clases en Ruby). Con nil deja el hueco vacío:

nada = nil
puts "Valor: [#{nada}]"   # Valor: []

puts, print y printf

Método Qué hace
puts (put string) Escribe el texto y añade un salto de línea al final
print Escribe el texto sin salto de línea
printf Escribe con un formato (%s, %d, %.2f…) y sin salto de línea
texto1 = "Hola"
texto2 = "Mundo"

puts "#{texto1} #{texto2}"
print "#{texto1} #{texto2}\n"
printf("%s %s\n", texto1, texto2)

# Hola Mundo
# Hola Mundo
# Hola Mundo

Formatear números: format

Cuando necesitas decimales fijos o ceros a la izquierda, format (o el operador %) devuelve el texto ya formateado:

puts format("%.2f €", 3.14159)   # 3.14 €
puts format("%05d", 42)          # 00042
puts "Precio: %.2f €" % 9.5      # Precio: 9.50 €

Con nombres y en columnas

Con varios valores, es fácil confundir el orden. format acepta nombres, con %<nombre>, y así cada hueco dice qué va en él:

puts format("%<producto>s: %<precio>.2f €", producto: "Pan", precio: 1.5)   # Pan: 1.50 €

Un número delante de la letra fija el ancho, y un -, que se alinee a la izquierda. Sirve para sacar tablas sencillas en la terminal:

[["Pan", 1.5], ["Leche", 0.99], ["Aceite", 12]].each do |producto, precio|
  puts format("%-8s%6.2f €", producto, precio)
end
Pan       1.50 €
Leche     0.99 €
Aceite   12.00 €

Textos de varias líneas: heredoc

Para textos largos, un heredoc (<<~) también interpola y quita la sangría común:

nombre = "Ana"
edad = 30

mensaje = <<~TEXTO
  Hola #{nombre},
  tienes #{edad} años.
TEXTO

puts mensaje
# Hola Ana,
# tienes 30 años.

Si quieres un heredoc que no interpole, pon el nombre entre comillas simples, igual que con un texto corto:

nombre = "Ana"
plantilla = <<~'TEXTO'
  Hola #{nombre}
TEXTO
puts plantilla   # Hola #{nombre}

Errores frecuentes

1. Olvidar las llaves o la almohadilla. Hacen falta las dos cosas, # y {}. Con solo una, el texto sale tal cual y no hay error:

nombre = "Ana"
puts "Hola #nombre"     # Hola #nombre
puts "Hola {nombre}"    # Hola {nombre}
puts "Hola #{nombre}"   # Hola Ana

2. Un hueco vacío que nadie ve. Como nil se convierte en texto vacío, un dato que falta no da error: deja un hueco. Pasa mucho con hashes cuyas claves son textos y no símbolos:

usuario = { "nombre" => "Ana" }
puts "Hola #{usuario[:nombre]}, bienvenida"   # Hola , bienvenida

Si el dato tiene que estar, pídelo con fetch, que falla en el sitio y te dice qué falta:

puts "Hola #{usuario.fetch(:nombre)}"   # el mismo usuario de arriba, con la clave "nombre"
key not found: :nombre (KeyError)

La diferencia entre "nombre" y :nombre se explica en Símbolos en Ruby.

3. Interpolar un objeto que no define to_s. Sale el nombre de la clase y una dirección de memoria:

class Coche
  def initialize(color) = @color = color
end

puts "Tu coche: #{Coche.new("rojo")}"
Tu coche: #<Coche:0x00007f006d443080>

Define to_s en la clase, como se explica en Clases en Ruby.

4. Dar a format menos valores que huecos. Al contrario que la interpolación, format sí avisa:

puts format("%s tiene %d años", "Ana")
too few arguments (ArgumentError)

5. Pasar un texto que no es un número a un hueco de número. %d convierte el valor con Integer(): "3" vale y 3.7 se queda en 3, pero "tres" no es un número:

puts format("%d unidades", "tres")
invalid value for Integer(): "tres" (ArgumentError)

Compruébalo con un test

El formato de un texto también es comportamiento, y un test lo fija. Este método prepara la etiqueta de precio de un producto. La primera versión, con interpolación directa, parece correcta:

require "minitest/autorun"

def etiqueta(producto, precio)
  "#{producto}: #{precio} €"
end

class EtiquetaTest < Minitest::Test
  def test_siempre_muestra_dos_decimales
    assert_equal "Pan: 1.50 €", etiqueta("Pan", 1.5)
  end
end
ruby etiqueta_test.rb
EtiquetaTest#test_siempre_muestra_dos_decimales [etiqueta_test.rb:9]:
Expected: "Pan: 1.50 €"
  Actual: "Pan: 1.5 €"

1.5 se convierte en "1.5", sin el cero. Con format, el test pasa, y uno más comprueba que se redondea al céntimo:

require "minitest/autorun"

def etiqueta(producto, precio)
  format("%<producto>s: %<precio>.2f €", producto: producto, precio: precio)
end

class EtiquetaTest < Minitest::Test
  def test_siempre_muestra_dos_decimales
    assert_equal "Pan: 1.50 €", etiqueta("Pan", 1.5)
    assert_equal "Leche: 1.00 €", etiqueta("Leche", 1)
  end

  def test_redondea_al_centimo
    assert_equal "Queso: 3.33 €", etiqueta("Queso", 10 / 3.0)
  end
end
2 runs, 3 assertions, 0 failures, 0 errors, 0 skips

Para empezar con tests en Ruby, lee la introducción al testing en Ruby.

Cuándo no interpolar

Interpolar es perfecto para mensajes, etiquetas y textos que lee una persona. Pero cuando el texto lo va a interpretar otro programa, meter datos de fuera puede cambiar lo que ese programa hace:

  • HTML. Si el dato viene de un usuario, puede traer etiquetas. Escápalo antes de meterlo:
require "erb"

comentario = "<script>alert('hola')</script>"
puts "<p>#{comentario}</p>"
puts "<p>#{ERB::Util.html_escape(comentario)}</p>"
<p><script>alert('hola')</script></p>
<p>&lt;script&gt;alert(&#39;hola&#39;)&lt;/script&gt;</p>

En la primera línea, el navegador ejecutaría el <script>; en la segunda, solo lo muestra. Las plantillas de Rails escapan por ti lo que pones con <%= %>, como se ve en la diferencia entre <% %> y <%= %>.

  • Comandos del sistema. system("echo #{nombre}") pasa el texto a la shell, y un ; en nombre cuela otro comando. Pasa cada argumento por separado: lo tienes en ejecución de comandos del sistema desde Ruby.
  • Consultas SQL. Por el mismo motivo, nunca metas datos del usuario en una consulta con #{}: es la puerta de la inyección SQL. Usa los parámetros de la librería de base de datos, que separan la consulta de los datos.

Ejercicio de cinco minutos

  1. Copia el primer test de etiqueta, comprueba que falla y arréglalo con format.
  2. Añade un test para un precio de 1234.5. ¿Qué devuelve format("%.2f", 1234.5)? ¿Pone separador de miles?
  3. Escribe un heredoc con tu nombre y tu edad interpolados. Después pon el nombre del heredoc entre comillas simples y mira qué cambia.

Fuentes

Comprobado en noviembre de 2026 en la documentación oficial de Ruby 4.0: literales de cadena e interpolación (escapar la # desactiva la interpolación; #@foo como atajo de #{@foo}; un heredoc con el identificador entre comillas simples no interpola), Kernel (puts, print, printf, format) y especificaciones de formato (referencias por nombre con %<nombre>, ancho y alineación).

Los ejemplos del artículo original se ejecutaron el 7 de noviembre de 2026 con Ruby 4.0.9 (imagen oficial ruby:latest de Docker). Los nuevos (escapar #{, #@nombre, format con nombres y columnas, el heredoc sin interpolación, los errores frecuentes, el test y el escapado de HTML con ERB::Util.html_escape) se han ejecutado el 11 de noviembre de 2026 en Docker con las imágenes ruby:3.4 (Ruby 3.4.12, Minitest 5.25.4) y ruby:4.0 (Ruby 4.0.9, Minitest 6.0.0), con la misma salida en las dos. Las salidas de error están recortadas a las líneas que importan; la dirección del objeto cambia en cada ejecución.