Las clases abiertas de Ruby
En Ruby, las clases nunca son cerradas: siempre puedes agregar métodos a una clase que ya existe. Lo anterior aplica tanto para las clases que tu escribes como para las clases estándar incluídas en Ruby. Todo lo que tienes que hacer es abrir la definición de una clase existente y el nuevo contenido que especifiques va a ser agregado.
En el ejemplo pasado, definimos la clase Motocicleta
en el archivo p030motocicleta.rb.
1 class Motocicleta 2 def initialize(marca, color) 3 # Variables de instancia 4 @marca = marca 5 @color = color 6 end 7 def arranca 8 if (@engineState) 9 puts 'Motor encendido' 10 else 11 @engineState = true 12 puts 'Motor apagado' 13 end 14 end 15 end
Posteriormente, en el archivo p031pruebamotocicleta 'abrimos' la clase
Motocicleta y definimos el método describe.
1 require 'p030motocicleta' 2 m = Motocicleta.new('Yamaha', 'rojo') 3 m.arranca 4 5 class Motocicleta 6 def describe 7 puts 'El color de la motocicleta es ' + @color 8 puts 'La marca de la motocicleta es ' + @marca 9 end 10 end 11 m.describe 12 m.arranca 13 puts self.class 14 puts self 15 puts Motocicleta.instance_methods(false).sort
Otro ejemplo: en el archivo p031babreperro.rb abrimos la clase
Perro que definimos anteriormente en el archivo p029perro.rb
y agregamos el método ladra_fuerte. (Observa que para poder abrir la clase,
necesitamos requerirla primero):
1 # primero necesitamos requerir el archivo 2 # donde se encuentra la definicion de la clase 3 # perro 4 require 'p029perro.rb' 5 6 # abrimos de la clase y definimos un método nuevo 7 class Perro 8 def ladra_fuerte 9 puts 'Woof! Woof!' 10 end 11 end 12 13 # inicializamos una instancia de la clase 14 d = Perro.new('Labrador', 'Benzy') 15 16 # podemos usar los metodos previamente definidos 17 # y el que acabamos de definir 18 d.ladra 19 d.ladra_fuerte 20 d.muestra
Si ejecutas este programa (y has seguido paso a paso los temas anteriores), el resultado tal vez no sea lo que tu esperas:
¿Qué está pasando?, ¿Por qué esa larga lista de métodos si en el archivo que estamos
ejecutando (p31abreperro.rb) sólo llamamos d.ladra, d.ladra_fuerte y
d.muestra?.
La respuesta es simple pero importante: al inicio del programa estamos incluyendo
el archivo p029perro, por lo tanto todo el codigo de ese
archivo es ejecutado, no sólo la definición de la clase.
Observa que en el archivo p029perro.rb hacemos llamadas a métodos que
imprimen a STDOUT (ed, llaman al método puts).
A continuación vemos otro ejemplo en donde agregamos un método a la clase String.
(p032micadena).1
1 class String 2 def invierte 3 puts self.reverse 4 end 5 end 6 cadena = "La ruta nos aporto otro paso natural!" 7 cadena.invierte
1 El método invierte no es en realidad muy útil, pero
sirve para ilustrar el punto.
La facilidad que tenemos de abrir cualquier clase, incluso las clases
built-in
como String y Numeric es un tema medular en el estudio de Ruby y
en la manera en que algunos programas en Ruby están escritos.
Rails hace uso extenso de esta característica de Ruby en el módulo ActiveSupport.
De hecho, cuando eres nuevo en Ruby y en Rails, puede ser confuso identificar qué métodos
son estándar en Ruby y qué métodos son definidos por Rails.
Por ejemplo, en el archivo lib/core_ext/integer/even_odd.rb, dentro de
ActiveSupport, se encuentra la definición del el método multiple_of? dentro
del módulo EvenOdd. (En realidad, el módulo EvenOdd está anidado dentro de otros módulos
pero para simplificar el ejemplo, eliminamos la ruta completa):
1 module EvenOdd 2 def multiple_of?(number) 3 self % number == 0 4 end 5 end 6
Nota que hasta aquí, no se ha abierto ninguna clase de Ruby.
Sin embargo, en el archivo lib/core_ext/integer/integer.rb encontramos:
1 # primero el archivo even_odd es requierido 2 require 'active_support/core_ext/integer/even_odd' 3 4 # se a bre la clase Integer 5 class Integer 6 # se incluye el módulo Integer 7 # recuerda que para sipmlificar el ejemplo, 8 # eliminamos el identificador completo del módulo 9 # EvenOdd 10 include EvenOdd 11 end 12 13 # Toma en cuenta que esto es esencialmente lo mismo que 14 # escribir: 15 # 16 # 17 # class Integer 18 # def multiple_of?(number) 19 # self % number == 0 20 # end 21 # end 22 # 23 # Los metodos definidos en un modulo 24 # son agregados como metodos de instancia 25 # a cualquier clase en la que incluyamos dicho 26 # modulo usando el keyword include. (mixins) 27 28
ActiveSupport es un ejemplo excelente de cómo podemos abrir las clases
en Ruby y agregar métodos. Si quieres explorar más en este tema, analiza la librería
Facets que contiene muchos
ejemplos útiles, incluyendo algunos de los que se usan en Rails (en particular Facets/CORE).

