Ejemplos de mixin en Ruby: include, extend y prepend
En Ruby una clase solo puede heredar de otra. Pero a veces quieres que clases muy distintas compartan un comportamiento, como saber escribirse con palabras o compararse entre sí. Para eso están los mixins: escribes los métodos en un módulo y los mezclas donde haga falta.
Es como un accesorio de un robot de cocina: la misma cuchilla de picar sirve en varios modelos, sin que tengas que comprar otro robot.
Estos son cuatro ejemplos, del más habitual al más específico.
1. include: mixin dentro de una clase
module Numerable
NOMBRES = { 1 => "uno", 2 => "dos", 3 => "tres" }.freeze
def to_s
NOMBRES.fetch(@number, "muchos")
end
end
class Contador
include Numerable # todos los objetos de Contador tienen to_s del módulo
attr_accessor :number
end
contador = Contador.new
contador.number = 3
puts contador # tres
otro = Contador.new
otro.number = 2
puts otro # dos
puts llama a to_s por ti, así que no hace falta escribir puts "#{contador.to_s}".
Ruby busca los métodos en una lista ordenada, la cadena de ancestros. Con include, el módulo se coloca justo después de la clase:
Contador.ancestors.first(3) # => [Contador, Numerable, Object]
2. extend: mixin en un solo objeto
class Marcador
attr_accessor :number
def to_s = @number.to_s
end
especial = Marcador.new
especial.extend(Numerable) # solo este objeto recibe los métodos del módulo
especial.number = 3
puts especial # tres
normal = Marcador.new
normal.number = 2
puts normal # 2
Fíjate en que Marcador ya tenía su propio to_s, y aun así especial usa el del módulo: extend coloca el módulo por delante de la clase, pero solo para ese objeto. El resto de objetos de Marcador no cambian.
Puedes verlo en la cadena de ancestros de ese objeto concreto (su «clase singleton», una clase oculta que solo tiene él):
especial.singleton_class.ancestors.first(3)
# => [#<Class:#<Marcador:0x...>>, Numerable, Marcador]
3. extend en la clase: métodos de clase
Si usas extend dentro de la clase, los métodos del módulo pasan a ser métodos de clase: se llaman sobre la clase, no sobre sus objetos.
module Saludo
def saludar = "Hey"
end
class Persona
extend Saludo # extend en vez de include
end
Persona.saludar # => "Hey"
Persona.new.saludar # NoMethodError: los objetos no tienen el método
4. prepend: envolver un método de la clase
Con prepend, el módulo se coloca antes que la clase en la cadena de ancestros. Así puede cambiar un método de la clase y llamar al original con super:
module EnMayusculas
def to_s = super.upcase
end
class Etiqueta
prepend EnMayusculas
def to_s = "hola"
end
puts Etiqueta.new # HOLA
Etiqueta.ancestors.first(3) # => [EnMayusculas, Etiqueta, Object]
Resumen
| Forma | Dónde van los métodos | Uso típico |
|---|---|---|
include Modulo |
En los objetos de la clase | Compartir comportamiento entre clases |
objeto.extend(Modulo) |
Solo en ese objeto | Darle algo especial a un objeto concreto |
extend Modulo (dentro de la clase) |
En la propia clase | Métodos de clase compartidos |
prepend Modulo |
En los objetos, por delante de la clase | Envolver o adornar métodos existentes |
to_s que encuentra. Lo que cambia entre las tres formas es dónde queda el módulo, en ámbar, respecto a la clase.Herencia para lo que algo es; mixins para lo que algo sabe hacer.
Para practicar, prueba el ejercicio práctico de módulos en Ruby. Y si trabajas con Rails, los concerns son mixins con algunas comodidades añadidas.
Fuentes
Comprobado en noviembre de 2026 en la documentación oficial de Ruby 4.0: Module (include, prepend, ancestors) y Object#extend.
Todos los ejemplos se han ejecutado en Docker con la imagen ruby:latest (Ruby 4.0.9). Respecto al original se ha cambiado el estilo del código al habitual en Ruby (nombres en snake_case, puts objeto en lugar de puts"#{objeto.to_s}") y se ha añadido el ejemplo de prepend.