💎 Ruby — 1995

⬅️ Atlas · 🗂️ Todas las fichas · 📚 Índice de clases

Ruby se diseñó con un criterio poco frecuente y declarado por su autor: la felicidad de quien programa. De esa decisión salieron un lenguaje extraordinariamente expresivo, un marco web que cambió la industria, y buena parte de las prácticas ágiles que hoy se dan por supuestas.

🎯 Por qué está en este programa

Ruby es un primo de la familia de scripting dinámico (Atlas), cuyos representantes en el núcleo son Python y PHP. Es uno de los tres primos que se verifican en CI en cada clase, junto a Perl y Lua.

Aporta al programa el modelo de objetos más puro de todos los lenguajes de uso masivo —todo es un objeto, incluidos los números y nil, como en Smalltalk (clase 111)— y los bloques, que son la forma más elegante de la clase 121 en un lenguaje mayoritario.

Año 1995; 1.9 con la máquina virtual YARV (2007); 3.0 en 2020
Autoría Yukihiro Matsumoto ("Matz"), Japón
Familia Scripting dinámico; con Smalltalk, Perl, Lisp y Eiffel dentro
Paradigma Orientado a objetos puro, con fuerte componente funcional
Tipado Dinámico y fuerte, con tipos gradual y opcionalmente comprobados (RBS)
Memoria Recolección de basura generacional e incremental
Ejecución Bytecode sobre YARV, con JIT (YJIT) desde 3.1
Estado 🟢 Muy vivo en web y automatización; Rails sigue siendo referencia

📜 Historia

Yukihiro Matsumoto quería, en 1993, un lenguaje de guion verdaderamente orientado a objetos. Perl era potente y no era OO; Python era OO y —en su opinión— no lo bastante. Su frase resume el criterio de diseño:

"Ruby está diseñado para hacer felices a los programadores."

Eso no es marketing: es una decisión de ingeniería con consecuencias. Cuando hay varias formas de escribir algo, Ruby suele permitir todas, y elige como idiomática la que se lee mejor en voz alta. Es lo contrario del "solo una forma obvia" de Python, y la comparación entre los dos es uno de los contrastes más instructivos de este Atlas.

Ruby fue popular en Japón durante años y desconocido fuera. En 2004, David Heinemeier Hansson publicó Ruby on Rails, y eso lo cambió todo: Rails llevó al mundo entero la convención sobre la configuración, los generadores de código, las migraciones de base de datos y una forma de trabajar que hoy está en Django, Laravel, Phoenix y media docena más.

Y con Rails llegó también una cultura de pruebas —RSpec, Cucumber, el desarrollo dirigido por pruebas como norma— que salió del ecosistema Ruby hacia todos los demás (clase 139).

Después vino la corrección del talón de Aquiles: YARV (1.9) sustituyó al intérprete de árbol, Ruby 3.0 (2020) cumplió el objetivo "Ruby 3x3" —tres veces más rápido que 2.0— y YJIT, escrito en Rust por Shopify, ha dado saltos grandes de rendimiento en producción real.

🏭 Dónde vive hoy

🧠 Lo que enseña: todo es un objeto, y los bloques

Uno, la pureza del modelo de objetos (clase 111):

5.class          # Integer
5.times { |i| puts i }
nil.to_a          # []      ← hasta nil es un objeto con métodos
Integer.ancestors # [Integer, Numeric, Comparable, Object, Kernel, BasicObject]

No hay tipos primitivos. En Java int no es un objeto y hay que envolverlo; en Ruby, como en Smalltalk, no existe esa distinción — y eso hace el lenguaje uniforme a costa de rendimiento, que es lo que YJIT recupera con las cachés de envío de la clase 152.

Dos, los bloques, que son la aportación más reconocible:

[1, 2, 3].map { |x| x * 2 }
File.open("datos.txt") do |f|      # ← el fichero se cierra SOLO al salir del bloque
  f.each_line { |l| puts l }
end

Un bloque es un trozo de código que se pasa a un método, y el método decide cuándo y cuántas veces ejecutarlo. Eso da a la vez iteración (clase 115) y gestión de recursos (clase 132) — el File.open con bloque es RAII sin destructores, y el with de Python y el try-with-resources de Java persiguen lo mismo con más ceremonia.

Y tres, las clases abiertas, que son su característica más potente y más peligrosa:

class String
  def gritar = upcase + "!"
end
"hola".gritar        # "HOLA!"

Se puede añadir un método a cualquier clase, incluidas las del sistema. Es lo que hace posible la expresividad de Rails —2.days.ago, "texto".pluralize— y también lo que produce el problema que la comunidad llama monkey patching: dos bibliotecas que parchean lo mismo, y un fallo que nadie sabe de dónde viene (clase 150).

Ruby lo reconoció y dio una solución (clase 146): los refinamientos (refine/using) limitan el parche al ámbito donde se activa. Es un buen ejemplo de un lenguaje corrigiendo su propio exceso sin quitar la característica.

🔄 Lo que se ha modernizado

⚙️ Cómo se ejecuta hoy

ruby main.rb < entrada.txt        # el comando de la clase 041

bundle install                     # dependencias, con Gemfile.lock (clase 143)
rubocop && rspec                    # estilo y pruebas (clases 139 y 146)
ruby --yjit main.rb                  # con el JIT activado

🧪 El programa de la clase 041 en Ruby

Esta versión se ejecuta y se verifica en CI contra el mismo casos.json que el núcleo.

precio, cantidad, descuento = STDIN.gets.split.map(&:to_f)
total = precio * cantidad * (1 - descuento)
puts format("Total: %.2f", total)

Lo que hay que ver.

📚 Fuentes y bibliografía


⏮️ Volver al Atlas · 🗂️ Todas las fichas · 🔗 Relacionadas: Python · Perl · Smalltalk · Elixir · Lua