29 ene. 2020

Los Módulos en Ruby (herencias cruzadas y mixin)

Ruby en línea: https://paiza.io/projects/3P-5xOa5TfPscvm1Npj98g?language=ruby

==================================================================

En Ruby todo es un objeto, pero los módulos son como una clase especial que no puede instanciarse, lo cual no es nada más que una posibilidad de clase tan limitada que se llama módulo.

Como su nombre indica, los módulos son construcciones para hacer cosas, estas cosas no pueden ser nada por sí mismas, pero pueden ser llamadas desde otros métodos, clases e instancias.

Pueden contener de todo; constantes, variables, métodos y clases.

Una forma de verlos es como una librería donde dejar una serie de variables, constantes, métodos y/o clases que pueden ser útiles desde fuera del método.

Su sintáxis es:

module Nombredelmódulo                        #empieza en mayúscula
.
.
.
end

Pueden estar escritos en el mismo fichero que el resto del programa, para lo cual han de ir antes de aquello que lo invoque y la manera de invocarlo es:

include Nombredelcontenidodelmodulo

Veamos un ejemplo:

module Saludar
    puts 'Este es mi saludo'
end

module Despedida
puts 'Ahora me despido'

class Persona

include Saludar
puts 'Hoooooola'
incluse Despedida
end

Ésto da la salida:

Este es mi saludo   # al entrar en la clase se salta al módulo Saludar y después vuelve a la clase
Ahora me despido   # ejecuta el otro módulo Despedida y regresa a la clase
Hoooooola

Nótese que los módulos que encuentre en la clase los ejecuta antes de continuar con la clase



28 ene. 2020

Las Clases y los Objetos creados por ellas PARTE 3

Para terminar, vamos a ver los tipos de alcances que pueden tener los métodos de una clase.

Pueden ser cuatro:
Público: lo será siempre que no se declare otra cosa e indica que son accesibles por cualquiera que llame al método de la clase, de cualquier objeto de la clase y él mismo (self).

class Persona
def initialize(edad)
@edad = edad
end

def edad
@edad
end

end

Pedro = Persona.new(25)
Juan = Persona.new(64)

puts Pedro.edad
puts Juan.edad

Esto nos da la salida esperada de 25 y 64 respectivamente

también se puede escribir así:

def adios           #este es de visibilidad pública
@adios
end
private :adios

Protegido: Los objetos no pueden acceder al método protegido, sólo son accesibles a los otros objetos de la misma clase o las subclases, es decir, los que heredan de la clase principal de la misma clase, pero nunca por el propio objeto.


class Persona

def initialize(edad)
@edad = edad
end

def edad                           # este es el método protegido, pero si lo declaramos aquí no funciona
@edad
end

def compararedad(op)                                        #op es otro objeto con el que se comparará
if op.edad > edad                                                #el objeto Juan si puedo consultar el dato de Pedro
'La edad de la otra persona es mayor'
else
'La edad de la otra persona es la misma o menos'
end

end
protected :edad                                                     #OJO aquí si funciona porque ya ha sido leído
end
Pedro = Persona.new(25)
Juan = Persona.new(64)


puts Pedro.compararedad(Juan)
puts Juan.edad

Esto dará la salida:
La edad de la otra persona es mayor
prueba1.rb:27:in `<main>': protected method `edad' called for #<Persona:0x02d94a28 @edad=64> (NoMethodError)

el error es porque ni Pedro ni Juan tienen acceso a su método edad


Privado: Sólo es accesible por el propio objeto, es decir por self, no se puede acceder al método mismo pero si a un método que llame a las variables que interese saber.

class Persona

def initialize(edad, altura)                       
@edad = edad
@altura = altura
end

def edad
@edad
end

def altura                               #este es un método público
@altura
end

def variables
#este método variables llama a las variables edad y altura
puts "Este es el valor de la variable edad = #{edad} y altura = #{altura}"

end
private :edad                                      # edad es el método privado
end
Pedro = Persona.new(33, 180)
Juan = Persona.new(64,258)

puts Pedro.variables
puts Juan.variables
puts Juan.altura
puts Juan.edad

Que da la salida:

Este es el valor de la variable edad = 33 y altura = 180

Este es el valor de la variable edad = 64 y altura = 258

258
prueba1.rb:28:in `<main>': private method `edad' called for #<Persona:0x02e745d0 @edad=64, @altura=258> (NoMethodError)


Si sustituirmos la última línea de código por:
Puts Juan.send :edad                                       #send es un método que permite acceder siempre
nos imprimirá el valor de ese método 64 que antes nos daba error.

24 ene. 2020

Las Clases y los Objetos creados por ellas PARTE 2

Parte 1 -> https://ruby.obdnet.com/2020/01/las-clases-y-los-objetos-creados-por.html

Refrencia:
https://carlossanchezperez.wordpress.com/2013/05/19/mi-guia-de-ruby-las-clases-y-curiosidades-oop/
https://medium.com/@gsanchezd/entendiendo-los-objetos-en-ruby-18bcce934d66


De la PARTE 1, nos queda claro que una clase es un objeto que hace objetos, que dentro de la clase se definen las características o propiedades que llevarán las instancias, es decir, todos los objetos que de ella salgan, esto se hace a través de métodos de objetos que manejan las variables de instancia, y que se pueden acceder a ellas, para lectura, escritura o para ambas, mediante métodos de objetos específicos, que apuntan a la misma variable solo que un método la invoca y el otro la escribe, esto se utiliza cuando se inizializan las variables de instancia, pero de no necesitarlo mediante la sentencia attr_ que puede ser attr_accessor que permite ambas cosas, attr_writer sólo para escritura y attr_reader para lectura solamente.

Una de las características interesantes de las clases es la Herencia:

Heredar significa que desde una clase se pueden invocar los parámetros de otra, recibiendo de ésta sus variables de clase, incluso pudiendo modificar a éstas.

class Animal

@@animal = "Ser vivo"               #Variable de clase
@ser_vivo = "soy un ser vivo"     #Variable de instancia

def self.pruebolaclase                    #Método de clase
puts "Estoy en self.pruebolaclase"
puts @@animal
puts @ser_vivo
puts "Salgo de self"
end

def pruebolaclase

puts "Estoy en el método de instancia"
puts @@animal
puts @ser_vivo
puts "Salgo del método de instancia"
end

end

Animal.pruebolaclase                    #
Animal.new.pruebolaclase

Esto arroja la salida:
Estoy en self.pruebolaclase
Ser vivo
soy un ser vivo
Salgo de self
Estoy en el método de instancia
Ser vivo

Salgo del método de instancia


Si creamos una clase Perros:

class Perros < Animal

def tipo
@tipo = "Cánidos"
end

end

Perros.pruebolaclase

Arroja la salida:

Estoy en self.pruebolaclase
Ser vivo

Salgo de self

y si pedimos puts Perros.new.tipo

Nos da la salida:
Estoy en self.pruebolaclase
Ser vivo

Salgo de self
Cánidos

Como vemos, Perros hereda la variable de la clase Animales pero sólo puede ver su propia variable de instancia.

Si desde Perros, variamos la variable de clase @@animal por @@animal = "Soy un animal" lo hereda tanto Perros como Animal.

class Animal

@@animal = "Ser vivo"               #Variable de clase
@ser_vivo = "soy un ser vivo"     #Variable de instancia

def self.pruebolaclase                    #Método de clase

puts "Estoy en self.pruebolaclase"
puts @@animal
puts @ser_vivo
puts "Salgo de self"

end

def pruebolaclase
puts "Estoy en el método de instancia"
puts @@animal
puts @ser_vivo
puts "Salgo del método de instancia"

end
end

class Perros < Animal
@@animal = "Soy un animal"
def tipo
@tipo = "Cánidos"
end
end

Animal.pruebolaclase
Perros.pruebolaclase
puts Perros.new.tipo

arroja la salida:
Estoy en self.pruebolaclase
Soy un animal
soy un ser vivo
Salgo de self
Estoy en self.pruebolaclase
Soy un animal

Salgo de self
Cánidos

Ya hemos visto que las clases tienen métodos propios y se invocan anteponiendo la instrucción self al método, pero ésto es sólo un método de clase, pues, en realidad, se pueden invocar declarando que ese método es de esa clase, en vez de poner self.nombremetodo se pondría nombreclase.nombremetodo.

Definimos una clase que calcule el área de un rectángulo y de el resultado en cm:

class Area
def Area.rectangulo(base, altura, unidades="cm")
area=base*altura
puts "El área del rectángulo es #{area} " + unidades
end
end

Area.rectangulo(3,5)

da la salida:
El área del rectángulo es 15 cm

y el programa:
class Area
def self.rectangulo(base, altura, unidades="cm")
area=base*altura
puts "El área del rectángulo es #{area} " + unidades
end
end

Area.rectangulo(3,5)

también da la salida:
El área del rectángulo es 15 cm

Cuando tenemos una clase y alguna subclase de ella, quizá nos interese nos interese poner el mismo método en ambas, solo que con contenidos distintos, así que cuando invoquemos el método de la subclase, podemos decirle que invoque al método con el mismo nombre de la clase madre y se complete con los parámetros de ambos. Esto se hace con el procedimiento super dentro de un método.

Veamos este ejemplo:

class Persona

def comer
puts 'comiendo'
end

end

class Trabajador < Persona
def comer
super
puts 'muy rápido'
end
end

Pedro = Trabajador.new

puts Pedro.comer

Que da la salida:

comiendo
muy rápido

Como se ve, super hace que acuda primero al método comer de Persona, coloca lo que esté y después sigue con el método comer de Trabajador.

Ahora bien, puede ser que una instancia concreta tenga que poseer un método concreto, y sólo ella, pues no se va a repetir, a esto se le llama método singleton, lo cual le otorga a esa instancia concreta los métodos propios de su clase y este nuevo,

Un ejemplo, imaginemos que en la clase Perro, todos labran pero habrá uno en concreto que hablará.

class Perro

def initialize(nombre)
@nombre = nombre
end

def ladrar
puts "Guau Guau"
end

end

perro1 = Perro.new('Chachi')
perro2 = Perro.new('Chulo')

def perro2.hablar          #este es el método singleton
puts 'Yo si que se hablar'
end

perro1.ladrar
perro2.ladrar

perro2.hablar
perro1.hablar

y da la salida:
Guau Guau
Guau Guau
Yo si que se hablar
prueba1.rb:26:in `<main>': undefined method `hablar' for #<Perro:0x02d64a40 @nombre="Chachi"> (NoMethodError)

El perro1 no puede acceder al método singleton de de perro2.

A su vez, también hay clase singleton, que se ejecuta sólo una vez en una sola instancia.

En este ejemplo:
class Perro

def initialize(nombre)
@nombre = nombre
end

def ladrar
puts "Guau Guau"
end

end

perro1 = Perro.new('Chachi')     #tiene que estar instanciado antes de la clase singleton
perro2 = Perro.new('Chulo')

class << perro1                           #estos << indica que es clase singleton
def hablar
return "Yo soy el que sabe hablar"
end

end

puts perro1.hablar

da la salida:
Yo soy el que sabe hablar

Esto quiere decir que al objeto perro1 se le agrega el método singleton hablar
https://www.youtube.com/watch?v=TcLYT7qCqwM&list=PLEFC2D43C36013A70&index=29