Métodos de clase en Ruby: self.metodo y class << self
Una clase es como el molde de una fábrica de galletas, y los objetos son las galletas. Los métodos de instancia los tiene cada galleta (galleta.comer). Los métodos de clase los tiene el molde: sirven para cosas que no dependen de una galleta concreta, como fabricar una de un tipo determinado (Galleta.de_chocolate).
Si todavía no has visto clases, empieza por Clases en Ruby.
Tres formas de definir un método de clase
class Demo
def Demo.metodo1 # con el nombre de la clase
"metodo1"
end
def self.metodo2 # con self: la forma más habitual
"metodo2"
end
class << self # un bloque para varios métodos de clase
def metodo3
"metodo3"
end
end
end
Demo.metodo1 # "metodo1"
Demo.metodo2 # "metodo2"
Demo.metodo3 # "metodo3"
Dentro de la definición de una clase, self es la propia clase, así que def self.metodo2 equivale a def Demo.metodo2. Se prefiere self porque, si renombras la clase, no tienes que tocar cada método.
Un método de clase no está disponible en los objetos:
Demo.new.metodo2
# NoMethodError: undefined method 'metodo2' for an instance of Demo
| Forma | Cuándo usarla |
|---|---|
def self.nombre |
La opción por defecto |
def Demo.nombre |
Funciona, pero repite el nombre de la clase |
class << self |
Cuando hay varios métodos de clase o quieres usar attr_reader o private para ellos |
Métodos de clase como constructores con nombre
new crea objetos, pero no dice qué tipo de objeto quieres. Un método de clase le pone nombre a la intención (a esto también se le llama método fábrica o pseudo-constructor):
class Forma
attr_reader :lados, :perimetro
def initialize(lados, perimetro)
@lados = lados
@perimetro = perimetro
end
def self.cuadrado(lado)
new(4, lado * 4)
end
def self.triangulo(lado)
new(3, lado * 3)
end
end
cuadrado = Forma.cuadrado(5)
p [cuadrado.lados, cuadrado.perimetro] # [4, 20]
Dentro del método de clase basta con new: ya estás en la clase, no hace falta escribir Forma.new.
Forma.cuadrado(5)se entiende mejor queForma.new(4, 20).
class << self con atributos de la clase
class << self es útil cuando la clase guarda datos propios. Aquí la clase cuenta cuántos usuarios ha creado:
class Usuario
@total = 0
class << self
attr_reader :total
def crear(nombre)
@total += 1
new
end
end
end
Usuario.crear("Ana")
Usuario.crear("Luis")
p Usuario.total # 2
Para guardar datos a nivel de clase hay varias opciones, con matices; los tienes en Variables de clase en Ruby.
Fuentes
- Métodos: definición con
self.yclass << self(Ruby 4.0). - Módulos y clases: métodos singleton (Ruby 4.0).
Todos los ejemplos se han ejecutado con Ruby 4.0.9 (imagen oficial ruby:latest de Docker) y las salidas de los comentarios son las reales.