0% encontró este documento útil (0 votos)
58 vistas

Ruby - Argentina Programa

Los objetos pueden representar cualquier entidad y resuelven problemas comunicándose mediante el envío de mensajes. Cada objeto tiene un estado definido por sus atributos y una interfaz de métodos que describen cómo responder a los mensajes. Los objetos interactúan a través de referencias en lugar de acceder directamente unos a otros.

Cargado por

gerardo
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
58 vistas

Ruby - Argentina Programa

Los objetos pueden representar cualquier entidad y resuelven problemas comunicándose mediante el envío de mensajes. Cada objeto tiene un estado definido por sus atributos y una interfaz de métodos que describen cómo responder a los mensajes. Los objetos interactúan a través de referencias en lugar de acceder directamente unos a otros.

Cargado por

gerardo
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 22

Objetos

Los objetos:

 Estos objetos pueden ser cualquier cosa, material o abstracta. Un objeto es cualquier entidad que pueda hacer
algo por nosotros para resolver un problema. Estos objetos viven dentro de un mismo mundo ( llamado
AMBIENTE) y cada uno de ellos va a tener distintas responsabilidades. Además, van a poder comunicarse entre
ellos mandándose mensajes.
 en un ambiente hay objetos que hacen cosas, y que nos comunicamos con ellos mediante el envío de mensajes.
 Que un objeto es la representación de algún aspecto del problema que queremos resolver.
 Que los objetos tienen identidad y saben diferenciarse de otros objetos.
 Que interactuamos con los objetos mediante el envío de mensajes.
o al conjunto de mensajes que un objeto entiende lo llamamos interfaz.
 Que si le enviamos un mensaje que no entiende, se produce un error.
 Los objetos tienen una o varias propiedades (atributos) que almacenan datos y estos valores pueden cambiar
con el tiempo. Al conjunto de estos atributos se lo denomina estado.

Cuando un resultado devuelve nil es un objeto que representa la nada

En Ruby, la definición de un objeto se inicia con la palabra reservada module, luego el nombre del objeto (con la
primera letra en mayúscula) y su fin se indica con un end.
Sintaxis:
module Nameobject
end
Ejemplo: si quisiéramos definir a un Objeto (ej: Norita), escribiríamos el siguiente código:
module Norita
end
Métodos o mensajes:
Para que un objeto entienda un mensaje debemos "enseñarle" cómo hacerlo, y para ello es necesario definir
un método (interfaz) dentro de ese objeto
Un método es, entonces, la descripción de qué hacer cuando se recibe un mensaje del mismo nombre.
Un mensaje / función se determina por:

 El nombre de la función
 La cantidad de parámetros que permite
Dos cosas muy importantes a tener en cuenta:
1- Todos los métodos comienzan con def y terminan con end. Luego el nombre del método precedido por self.
( self.nameMeto ). “self.”  Un método es, entonces, la descripción de qué hacer cuando se recibe un mensaje
del mismo nombre.
Si nos falta alguna de estos dos, la computadora no va a entender nuestra solución.
2- Todos los métodos que pertenezcan al mismo objeto van dentro del mismo module.
Sintaxis:
module Nameobject
def nameMetodo
end
end
Convención en los nombres de metodos:
1- nameMetodo  solo es un procedimiento.
2- nameMetodo! hacen algo, es acción
3- nameMetodo? devuelven un booleano
Crear métodos getters y setters para un ATRIBUTO
4- Setter: nameMetodo= (parámetro/s)  modifican el estado de un atributo… Llevan el mismo nombre del
atributo que modifica seguido del operador =
5- Getter: nameMetodo  devuelven el valor de los atributos. Se escriben exactamente el mismo nombre que el
atributo del cual devuelven el valor, pero sin el @

1- Aquellos métodos que solo son un procedimiento, no se le agrega nada:


a. Ejemplo:
Object.energía
Object.nombre

2- Aquellos métodos / mensajes con efecto (es decir, que hacen algo) les pondremos un signo de exclamación
( ! ) al final.

a. Ejemplo:
Object.cantar! : hace que cante;
Object.comer_lombriz! : hace que coma una lombriz;
Object.volar_en_circulos! : hace que vuele en círculos.
Object.volar_hacia! parametro : Vuela al lugar indicado
Object.energia : nos dice cuanta energía tiene (un número);

3- Aquellos métodos / mensajes que devuelven booleanos (o sea, verdadero o falso) terminen con un ?
a. Ejemplo:
Object.débil?
Object.feliz?
Metodos en literales:

todas nuestras interacciones en un ambiente de objetos ocurren enviando mensajes y las operaciones
aritméticas no son la excepción a esta regla.

En el caso de 2 + 3 podemos hacer el mismo análisis:

 el objeto receptor es 2;


 el mensaje es +;
 el argumento es 3.

Y de hecho, ¡también podemos escribirlo como un envío de mensajes convencional!

Probá en la consola los siguientes envíos de mensajes:

Ejemplo 1: 5.+ 6
Ejemplo 2: 3.< 27

Ejemplo 3: Pepita.== Norita

Métodos / objetos de ruby:


Object.abs //retorna el valor absoluto de un numero
numero.times { repetir instrucciones la cantidad de veces indicada en número }

SETTER y GETTER:
A los mensajes que modifican el estado de un objeto, es decir, alguno de sus atributos. A estos mensajes que solo
modifican un atributo los conocemos con el nombre de setters, porque vienen del inglés set que significa establecer,
ajustar, fijar.
Para estos casos, solemos utilizar una convención que se asemeja a la forma que se modifican los atributos desde el
propio objeto, pudiendo ejecutar el siguiente código desde una consola:
Emilce.ave = Pepita
Esto se logra definiendo el método ave=, todo junto, como se ve a continuación:
module Emilce
def self.ave=(ave_nueva)
@ave = ave_nueva
end
def self.entrenar_ave!
53.times { @ave.volar_en_circulos! }
@ave.comer_alpiste!(8)
end
end
Como ya te habíamos contado en una lección anterior, a estos métodos que solo sirven para acceder o modificar un
atributo los llamamos métodos de acceso o accessors. Repasando, los setters son aquellos métodos que establecen el
valor del atributo. Mientras que los getters son aquellos que devuelven el valor del atributo.
La convención en Ruby para estos métodos es:

 Los setters deben llevar el mismo nombre del atributo al que están asociados, agregando un = al final.
 Los getters usan exactamente el mismo nombre que el atributo del cual devuelven el valor pero sin el @.
 Aquellos getters que devuelven el valor de un atributo booleano llevan ? al final.

Ejemplo:
module Manuelita
@energia = 100
@ciudad = Pehuajo
@mineral_preferido = Malaquita
@donde_va = Paris
def self.energia //Metodo Getter
@energia
end
def self.ciudad //Metodo Getter
@ciudad
end
def self.mineral_preferido=(mineral) //Metodo Setter
@mineral_preferido = mineral
end
def self.mineral_preferido //Metodo Getter
@mineral_preferido
end
def self.donde_va=(ciudad) //Metodo Setter
@donde_va = ciudad
end
end

Propiedades(atributos)
Las propiedades son un atributo de nuestro objeto. Las propiedades comienzan con el símbolo arroba @, ejemplo
@namePropiedad.
Las propiedades son objetos que nos permiten representar una característica de otro objeto. Un objeto conoce a todos
sus atributos por lo que puede enviarles mensajes.
Los objetos pueden tener múltiples atributos y al conjunto de estos atributos se lo denomina estado
El estado es siempre privado, es decir, solo el objeto puede utilizar sus atributos.

Argumentos:

Un mensaje podría no tener o tomar uno o más de un argumento, separados por coma.

Un detalle: en Ruby, a veces, los paréntesis son opcionales. Por eso, cuando no sean imprescindibles
los omitiremos.
Objetc.mensaje argumento => Pepita.comer_alpiste! 39
Objetc.mensaje ( argumento ) => Pepita.comer_alpiste! ( 39 )
SELF

Un objeto puede enviarse un mensaje a sí mismo fácilmente usando self como receptor del mensaje.

Polimorfismo y encapsulamiento
Polomorfismo: Decimos entonces que dos objetos son polimórficos cuando pueden responder a un mismo conjunto de
mensajes (métodos) y hay un tercer objeto que los usa indistintamente. Dicho de otra forma, dos objetos son
polimórficos para un tercer objeto cuando este puede enviarles los mismos mensajes, sin importar cómo respondan o
qué otros mensajes entiendan.

Entender un mismo mensaje, pero pueden comportarse de formas diferentes.


Este principio fundamental del paradigma de objetos nos permite que podamos interactuar de igual manera con
diferentes objetos, con el único requisito de que todos ellos entiendan el o los mensajes que necesitamos enviarles.
Encapsulamiento: Si hacemos bien las cosas, quien use nuestros objetos sólo verá lo que necesite para poder
interactuar con ellos. A esta idea la conocemos como encapsulamiento, y es esencial para la separación
de responsabilidades de la que veníamos hablando.

Será tarea tuya (y de tu equipo de trabajo, claro) decidir qué atributos exponer en cada objeto (getter y setter). Es
decir, haciendo que cada objeto solo exponga lo necesario para interactuar con él y se reserve para su ámbito privado
lo que no sea necesario compartir.

En el caso de los atributos, esta exposición se logra implementando un getter (método que nos permite ver su valor) o
un setter (método que nos permite modificar su valor). Y que nuestro código sea entendido fácilmente por otras
personas, elegimos utilizar una convención para darle nombre a estos métodos.

Repetir código:
numero.times { repetir instrucciones la cantidad de veces indicada en número }

Condicionales:
If
Instrucciones 1
elseif
Instrucciones 2
else
Instrucciones 3
end
Las variables son referencias

En un ambiente hay muchos objetos, pero en realidad no interactuamos con ellos directamente, sino a través de
referencias, que son nombres o etiquetas que les damos a los objetos.

Para un objeto pueden existir múltiples nombres: cuando le damos uno nuevo, no estamos creando una copia del
objeto ni modificándolo realmente, sino que estamos creando una nueva referencia que apunta al objeto. Así que ¡ojo!,
si compartís un objeto con otros, y lo mutás, ¡todos los que tengan una referencia al mismo verán los cambios!

Finalmente, en objetos, todo lo que se parezca a una variable es una referencia, y hay de muchos tipos:

 variables de un programa
 variables locales de un método
 parámetros de un método
 atributos de un objeto
 y el nombre global de un objeto bien conocido.

Entonces no conocemos a los objetos directamente, sino a través de etiquetas llamadas referencias. Entonces cuando
tenemos una declaración de variable como ésta...

saludo = "hola"

la variable es una etiqueta llamada referencias.

...lo que estamos haciendo es crear una referencia saludo que apunta al objeto "hola", que representamos mediante
una flechita:

Como vemos, los objetos son las "bolitas" y las referencias, las "flechitas". Pero, ¿cuál es la diferencia entre variable y
referencia?

Diagrama de objetos con el objeto 'hola' y una referencia saludo al mismo

Y cuando tenemos...

saludo.upcase

...le estamos enviando el mensaje upcase al objeto "hola", a través de la referencia saludo, que es una variable.

Sucede que hay muchos tipos de referencias, y una de ellas son las variables del programa. Pero, ¿no podíamos
enviarles mensajes "directamente" al objeto? Por ejemplo, ¿dónde están las referencias en estos casos?:
 ¿A qué referencia el envío upcase?  "ni hao".upcase
 ¿Y a qué referencia el envío size?  saludo.upcase.size

¡Simple! Cuando enviamos mensajes a objetos literales como el 2, el true u "hola" , o expresiones, estamos conociendo
a esos objetos a través de referencias implícitas, que son temporales (sólo existen durante ese envío de mensajes) y
anónimas (no tienen un nombre asociado).

 "hola".upcase  Acá hay una referencia implícita al objeto "hola"


 saludo.upcase.size  Y acá, otra referencia explícita al objeto "HOLA"

Las referencias explícitas son las que vimos hasta ahora. Por ejemplo: saludoEnChino = "ni hao"

Múltiples referencias
 otro_saludo = "buen día"  se crea la variable otro_saludo que referencia al objeto "buen día"
 despedida = otro_saludo  se crea la variable despedida que, por asignarle la referencia otro_saludo, apunta al
mismo objeto "buen día"

Caso 1:

 "buen día".equal? "buen día" => false


 despedida.equal? "buen día" => false

En ambos casos el resultado fue false, dado que aquellos strings son objetos distintos, a pesar de que tengan los
mismos caracteres. Cada vez que escribimos un string estamos creando un nuevo objeto. Sin embargo:

Caso 2:

 otro_saludo.equal? otro_saludo => true


 despedida.equal? otro_saludo => true

¿Por qué? ¡Simple! Ambas referencias, otro_saludo y despedida, apuntan al mismo objeto. La moraleja es que declarar
una variable significa agregar una nueva referencia al objeto existente, en lugar de copiarlo:
Distinto sería si hacemos:

Caso 3:

 otro_saludo = "buen día"


 despedida = "buen día"

Lo cual da como resultado este ambiente:

Veamos otro ejemplo. Si tuvieramos el siguiente código...

 persona = "Graciela"
 hija_de_hector = "Graciela"
 hermana_de_tito = persona
 hija_de_elena = "Gracielita"
 hermana_de_ana = hermana_de_tito
 mama_de_gustavo = "hermana_de_ana"
 tia_de_gonzalo = hija_de_hector

... podríamos decir que solo hermana_de_tito y hermana_de_ana referencian al mismo objeto que persona.

Ya entendimos que dos strings con el mismo contenido no necesariamente son el mismo objeto. Pero esto puede ser
poco práctico. ¿Cómo hacemos si realmente queremos saber si dos objetos, pese a no ser el mismo, tienen el mismo
estado?
Equivalencia
Entonces, ¿qué pasa si lo que quiero es comparar los objetos no por su identidad, sino por que representen la misma
cosa?

Pensemos un caso concreto. ¿Hay forma de saber si dos strings representan la misma secuencia de caracteres más allá
de que no sean el mismo objeto? ¡Por supuesto que la hay! Y no debería sorprendernos a esta altura que se trate de
otro mensaje:

 "hola" == "hola" => true


 "hola" == "adiós" => false
 "hola".equal? "hola" => false

El mensaje == nos permite comparar dos objetos por equivalencia; lo cual se da típicamente cuando los objetos tienen
el mismo estado. Y como vemos, puede devolver true, aún cuando los dos objetos no sean el mismo.

Por ejemplo, en este caso...

procer = "San Martín"

avenida = "San Martín"

ciudad = "San Martín"

... las 3 referencias distintas (Variables distintas) apuntan a objetos distintos pero equivalentes entre sí, pero no
idénticos.

¡Cuidado! A diferencia de la identidad, que todos los objetos la entienden sin tener que hacer nada especial, la
equivalencia es un poco más complicada.

Por defecto, si bien todos los objetos también la entienden, delega en la identidad, así que muchas veces es lo mismo
enviar uno u otro mensaje;

y para que realmente compare a los objetos por su estado, vos tenés que implementar este método a mano en cada
objeto que crees. Los siguientes objetos ya la implementan:

 Listas
 Números
 Strings
 Booleanos

Objetos bien conocidos


¿Y qué hay de los objetos que veníamos definiendo hasta ahora? Por ejemplo a Fito, le aumenta la felicidad cuando
come:

module Fito
@felicidad = 100

def self.comer! (calorias)


@felicidad += calorias * 0.001
end

def self.felicidad
@felicidad
end
end

A objetos como Fito se los conocen como objetos bien conocidos: cuando los definimos no sólo describimos su
comportamiento ( comer!(calorias) y felicidad ) y estado ( @felicidad ), sino que además les damos un nombre o
etiqueta a través de la cual podemos conocerlos. ¿Te suena?

¡Adiviná! Esas etiquetas también son referencias. Y son globales, es decir que cualquier objeto o programa puede
utilizarla.

Veamos si va quedando claro. Definí un objeto AbuelaClotilde que entienda un mensaje alimentar_nieto ! , que haga
comer! 2 veces a Fito: primero con 2000 calorias, y luego con 1000 calorías;

ACLARACION: #Ya declaramos a Fito por vos.

module AbuelaClotilde
def self.alimentar_nieto!
Fito.comer! 2000
Fito.comer! 1000
end
end

¡Muy bien! Tu solución pasó todas las pruebas

Muchas veces, en lugar de decir tal cual como corresponde que le enviamos un mensaje al objeto apuntado
por la referencia Fito, podemos llegar a decir…

 enviar un mensaje a la variable Fito ...o...


 enviar un mensaje al objeto Fito ...o simplemente...
 enviar un mensaje a Fito

...porque si bien no es del todo correcto, es más breve. Lo importante es que entiendas que siempre estamos enviando
el mensaje al objeto a través de una referencia.

Atributos y parámetros
Además de los que ya vimos, hay más tipos de referencias: los atributos.

Por ejemplo, si la golondrina Pepita conoce siempre su ciudad actual...

module Pepita
@energia = 100

def self.volar_en_circulos!
@energia -= 10
end

def self.ciudad=( una_ciudad )


@ciudad = una_ciudad
end

def self.ciudad
@ciudad
end
end

Y en algún momento esta ( @ciudad ) pasa a ser Iruya (creada como un objeto anterior mente), el diagrama de objetos
será el siguiente:

Nuevamente, acá vemos otro caso de múltiples referencias: el objeto que representa a la ciudad de Iruya es
globalmente conocido como Iruya, y también conocido por Pepita como ciudad.

Miremos este código con más detenimiento:

@energia=100

def self.volar_en_circulos!
@energia = @energia - 10
End

Lo que estamos haciendo es cambiar la energía de Pepita: pasa de su valor actual, @energia, a ese valor menos 10. Por
ejemplo, pasa de 100 a 90. ¿Significa esto que el 100 se transforma en un 90 ?

No, en absoluto. @energia es una referencia a un objeto, que inicialmente apunta al objeto 100:
Luego, la operación de asignación cambia ese apuntador, que pasa a referenciar al 90:

¡Veamos si se entiende!

En este código...

module Pepita
@energia = 100

def self.volar_en_circulos!
@energia -= 10
end

def self.ciudad= ( una_ciudad )


@ciudad = una_ciudad
end
end

module Iruya
end

...si bien:

Pepita e Iruya son objetos bien conocidos;


@energia y @ciudad son atributos;
y una_ciudad es un parámetro;

¡Todas son referencias!

LISTAS/ COLECCIONES
Todas las colecciones entienden una serie de mensajes que representan operaciones o consultas básicas sobre la
colección.

Mensajes Polimórficos a todos los tipos de colecciones / listas. Es decir, que los siguientes métodos/funciones se pueden utilizar en
distintos objetos ( array , set , etc)

 Agregar el elemento pasado como parámetro a la lista:


nameArray.push elemento

 Eliminar el elemento pasado como parámetro a la lista:


nameArray.delete elemento

 Indica la cantidad de elementos que tiene la lista


nameArray.size

 Indica si la lista contiene el elemento pasado como parámetro


nameArray.include? elemento

 Metodos para encontrar elementos que cumplen con la condición indicada:


 .find parámetro . Este método devuelve únicamente 1er elemento que cumpla con la condición, solo un (1)
elemento o nil si no encuentra ninguna coincidencia.
 .select parámetro. Este método devuelve una colección con todos los elementos que cumplen con la
condición indicada. El valor de retorno es una colección
Para ambos la sintaxis es la misma: El método recibe: un bloque. Dicho bloque tiene un parámetro que
representa un elemento de la colección y una condición booleana como código, y lo que devuelve es una
nueva colección con los elementos que la cumplen.
nameArray.select { | parámetro | condición boolean a cumplir }
Ejemplo:
- algunos_numeros = [1, 2, 3, 4, 5]
- mayores_a_3 = algunos_numeros.select { |un_numero| un_numero > 3 }
- mayores_a_3
- [4, 5]

 .all? Sirve para saber si todos los elementos de una colección cumplen un cierto criterio. El mensaje .all?, recibe un bloque
como parámetro.. El valor de retorno es un booleano
nameArray.all? { | parámetro | condición boolean a cumplir }
Ejemplo: estudiantes.all? { |un_estudiante| un_estudiante.aprobo? }

 .any? saber si algún elemento de la colección cumple cierta condición. El mensaje .any?, recibe un bloque como parámetro..
El valor de retorno es un booleano
Ejemplo: estudiantes.any? { |un_estudiante| un_estudiante.aprobo? }

 .map El mensaje map nos permite, a partir de una colección, obtener otra colección con cada uno de los resultados que
retorna un envío de mensaje a cada elemento. Es decir, la nueva colección tendrá lo que devuelve el mensaje que se le envíe
a cada uno de los elementos. El mensaje .map, recibe un bloque como parámetro. El valor de retorno es: un colección , que
almacena un resultado para cada objeto de la colección.. Este resultado, depende del mensaje enviado a través del bloque
para cada objeto que tenga la colección a la cual se aplicó el .map
Ejemplo:
[Pepita, Norita].map { |una_golondrina| una_golondrina.energia }
=> [77, 52]

 .count nos dice cuántos elementos de una colección cumplen la condición. El mensaje .count , recibe un bloque como
parámetro.

Ejemplo: estudiantes.count { |un_estudiante| un_estudiante.aprobo? }


 .sum nos devuelve la sumatoria de todos los elementos. El mensaje .suma , recibe un bloque como parámetro..

Ejemplo: estudiantes.sum { |un_estudiante| un_estudiante.nota_en_examen }

 .each hace que cada objeto de la colección ejecute la funcion que se le pasa al bloque

 Object1.equal? Object2 nos dice si dos objetos son el mismo.

 Ejemplo: estudiantes.sum { |un_estudiante| un_estudiante.nota_en_examen +=1 }

COLECCIONES : ARRAY y SET


1- ARRAYS
Métodos propios de Array

 .first
nameArray.first Nos retorna el primer elemento de la lista
 .last
nameArray.last Nos retorna el último elemento de la lista
 .index
nameArray.index Nos retorna la posición de un elemento en la lista

Ejemplo:
un objeto Juegoteca que tenga un atributo @juegos con su correspondiente getter. La Juegoteca tiene que tener en
primer lugar el juego CarlosDuty, luego TimbaElLeon y por último Metroide.

module Juegoteca
@juegos = [ CarlosDuty , TimbaElLeon , Metroide ]
def self.juegos
@juegos
end
end

2- SET (conjuntos)
Tienen algunas diferencias con las listas (arrays):

 no admiten elementos repetidos;


 sus elementos no tienen un orden determinado.

Métodos propios de SET

Ejemplo:
Dada una lista determinada con la siguiente información: numeros_aleatorios = [ 1,27,8,7,8,27,87,1 ]

Los siguientes métodos retornarían los siguientes valores;

 .to_set
numeros_aleatorios.to_set , el resultado es: { 1, 27, 8, 7, 87 } //esto se debe a que no admite elementos
duplicados y los elimina.

 .first
numeros_aleatorios.first  Nos retorna: 1 // retorna el primer elemento de la lista

 .last
numeros_aleatorios.last  Nos retorna: 87 // retorna el último de la lista

 .index elementoABuscar
numeros_aleatorios.index 7  Nos retorna: // retorna la posición de un elemento en la lista

BLOQUES

Los bloques son objetos. Objetos que representan un mensaje o una secuencia de envíos de mensajes, sin ejecutar,
lista para ser evaluada cuando corresponda.
La palabra con la que se definen los bloques en Ruby es proc.

Ejemplo 1- en este caso le asignamos un bloque a incrementador:

un_numero = 7
incrementador = proc { un_numero = un_numero + 1 }

Ahora avancemos un pasito:

Metodo: .Call  se le pasa este método al bloque (objeto) cuando se quiere ejecutar el código que se encuentra
dentro del bloque.

Ejemplo 2: en este caso al bloque de duplicador le enviamos el mensaje (método o funcion) .call. Este mensaje le
indica al bloque que evalúe (ejecute) la secuencia de envíos de mensajes dentro de él.

otro_numero = 5
duplicador = proc { otro_numero = otro_numero * 2 }.call
En el Ejemplo 1 la secuencia de envío de mensajes dentro del bloque está sin ejecutar ya que NO tiene el mensaje
asignado .call .En cambio, en el ejemplo 2 estamos enviando el mensaje .call .

Por lo tanto:
- En el ejemplo 1, un_numero vale 7, porque el bloque incrementador no está aplicado. Por tanto, no se le suma 1.
- En el ejemplo 2, otro_numero vale 10, porque el bloque duplicador se ejecuta mediante el envío de mensaje .call,
que hace que se ejecute el código dentro del bloque. Por tanto, se duplica su valor.

Argumentos en el bloque
Los bloques también pueden recibir argumentos para su aplicación. 
Se detallan al comienzo del bloque entre 2 barras verticales y si tiene mas de uno se separan por una coma (
,):

Crear bloque con parametros : nameVariable = proc { | param1 , param2 | código }


Ejecutar bloque pasando los argumentos: nameVariable.call( valor1 , valor2 )

Ejemplo:
un_numero = 3

// Crear bloque con los argumentos encesarios


sumar_otros_dos = proc { |sumando1, sumando2| un_numero = un_numero + sumando1 + sumando2 }

// Ejecutar bloque pasándole los argumentos correspondientes


sumar_otros_dos.call(1 , 2)

CLASES E INSTANCIAS
Si tenemos más de un objeto que se comporta exactamente de la misma forma, lo que podemos hacer es generalizar
ese comportamiento definiendo una clase.
Las clases sólo nos sirven para generalizar objetos que tengan el mismo comportamiento: mismos métodos y mismos
atributos.

Ejemplo 1: creando cada objeto uno por uno


Si tenemos dos celulares con el mismo saldo y ambos tienen las mismas funcionalidades, realizar_llamada! y
cargar_saldo!:

1- Creamos el 1er objeto manualmente

module CelularDeMaría
@saldo = 25

def self.realizar_llamada!
@saldo -= 5
end

def self.cargar_saldo!(pesos)
@saldo += pesos
end
end

2- Creamos el 2do objeto manualmente:

module CelularDeLucrecia
@saldo = 25

def self.realizar_llamada!
@saldo -= 5
end

def self.cargar_saldo!(pesos)
@saldo += pesos
end
end
Ejemplo 2: Podemos generalizarlos en una clase
Para no copiar y pegar tantas veces el mismo codigo podríamos simplificarlo y crear una sola clase que luego sirva para
crear con una simple instrucción la cantidad de objetos que necesitemos. Se utiliza class para definirla

class Celular
def initialize
@saldo = 25
end

def realizar_llamada!
@saldo -= 5
end

def cargar_saldo!(pesos)
@saldo += pesos
end
end

Clases
La clase es un objeto que nos sirve como molde para crear / instanciar  nuevos objetos. El nombre de las
clases y objetos se escriben en minúscula y si tiene mas de una palabra la primer letra se escribe en
Mayuscula… La diferencia entre nombres de clases y objetos es :
 Clases: la primera letra comienza siempre en MAYUSCULA
 Objeto: la primera letra comienza siempre en minúscula. Ya que son variables: en particular, son
referencias que apuntan a instancias de Clases.

Método global .new :

todas las clases, entiende el mensaje .new, que crea una nueva instancia de esa clase.

Ejemplo nameObject= NameClase.new

Todas las clases entienden este método, independientemente de que la clase ya este creada por el lenguaje o
que la clase sea creada nosotros.

Crear un objeto a partir de una clase ya creada:

Ejemplo: Objeto1 = NameClase.new

CONSTRUCTOR
Método global .initiazlize ( parámetro 1 , parametro2 )
Este método se utiliza para decirle a la clase cómo querés que se construyan sus instancias / objeto.

Al trabajar con clases tenemos que inicializar los atributos en algún lugar. ¡Para eso es que existe ese método!

El mensaje .initialize nos permite especificar cómo queremos que se inicialice la instancia de una clase.
Este método puede recibir parámetros que especifiquen con qué valores deseamos inicializar los atributos
al construir nuestros objetos.

Ejemplo:

class Planta
def initialize( centimetros )
@altura = centimetros
end

def regar!
@altura += 2
end
end

Herencia
Cuando varios objetos tienen comportamiento en común podemos crear una clase que lo agrupe. Allí se define ese
comportamiento para evitar la repetición de lógica entre los distintos objetos.

Sin embargo, cuando tenemos clases que tienen una parte de comportamiento común, pero otra que difiere,
utilizaremos las herramientas de HERENCIA

Ejemplo sin Herencia:


class Celular
def initialize
@bateria=100
end

def utilizar!(minutos)
@bateria-= minutos/2
end

def cargar_a_tope!
@bateria=100
end
end

class Notebook
def initialize
@bateria=100
end

def utilizar!(minutos)
@bateria-= minutos
end
def cargar_a_tope!
@bateria=100
end
end

Comentarios:
- Las clases Celular y Notebook son demasiado parecidas, ¿no?
- Más específicamente en los métodos initialize y cargar_a_tope! son iguales. Ambas también comparten utilizar!
pero internamente realizan acciones distintas y por este motivo no se pueden crear una sola clase que englobe a
las 2 por esa sola sutil diferencia.
- ¡Obviamente se puede evitar esa repetición de lógica! Veamos:

superclase
Una forma de organizar las clases cuando programamos en objetos es establecer una jerarquía.
En nuestro caso podemos pensar que Celular y Notebook se pueden englobar en algo más grande que las incluya, la
idea de Dispositivo.

Muchas veces esa jerarquía se puede visualizar en el mundo real. Ejemplo:


- Perro y Gato entran en la categoría Mascota,
- Condor y Halcon se pueden clasificar como Ave.

Cuando programemos, la jerarquía que utilicemos dependerá de nuestro modelo y de las abstracciones que utilicemos.

//SUPER CLASE
class Ave
def volar!
@energia -= 20
end
end

//SUB CLASE
class Condor < Ave
def dormir!(minutos)
@energia += minutos * 3
end
end

//SUB CLASE
class Halcon < Ave
def dormir!(minutos)
@energia += minutos
end
end

El símbolo < significa "hereda de": por ejemplo, Condor hereda de Ave, que está más arriba en la jerarquía. Otra
manera de decirlo es que cada Condor es un Ave .

La herencia nos permite que las subclases (Condor y Halcon) posean los mismos métodos y atributos que la superclase
Ave. Es decir, las instancias de Condor y de Halcon van a saber volar! de la misma forma, pero cuando les enviemos el
mensaje dormir! cada una hará algo diferente.

En orden primero se definen las SUPER CLASES y luego se definen las SUB CLASES
Para recapitular, cuando dos objetos repiten lógica, creamos una clase con el comportamiento en común. En
el caso que dos clases repitan lógica, pero añadan cada una comportamientos diferentes deberíamos crear
una nueva clase a la cual llamamos superclase. A esta nueva clase llevaremos los métodos repetidos y
haremos que las clases originales hereden de ella. Estas subclases que heredan de la superclase solo
contendrán su comportamiento particular.

Clases Abstractas (Super Clase) y Clases Concretas (Sub clase)


Sabiendo que contamos con las clases Celular y Notebook, ¿alguna vez instanciaremos un objeto de la clase
Dispositivo? ¡Probablemente no! ¿Por qué querríamos crear algo tan genérico si podemos crear algo más
específico?

A este tipo de clases, como Dispositivo o Ave en el ejemplo del ejercicio anterior, se las llama clases abstractas
porque, a diferencia de las clases concretas (como Celular o Notebook), nunca las instanciamos. En otras
palabras, no creamos objetos con esa clase, solo nos sirven para proveer comportamiento a sus subclases.

Esto de la herencia está buenísimo. Porque nos permite heredar el comportamiento de una superclase pero redefinir
aquellas cosas que nuestras subclases hacen distinto. Pero cuidado, si tenemos que redefinir todo probablemente no
necesitemos heredar en primer lugar.

REDEFINIR METODOS DE UNA SUPER CLASE EN UN SUB CLASE

Para ello utilizamos el mensaje super


Al utilizar super en el método de una subclase, se evalúa el método con el mismo nombre de su superclase. Es decir nos
trae la misma funcionalidad del método definido en la SUPER CLASE ( para no repetir código) y luego agregamos lo que
nosotros queramos a dicho meto.

class Saludo

def saludar
"Buen día"
End
end

class SaludoDocente < Saludo

def saludar
super + " estudiantes"
end
end

De esta forma, al enviar el mensaje saludar a SaludoDocente, super invoca el método saludar de su superclase, Saludo.

Recordá que la herencia es un concepto amplio que tiene muchas variantes: primero vimos clases abstractas,
que no se instancian. También aprendimos a redefinir los métodos cuando heredamos un método pero
queremos que se comporte de otra forma.

Luego vimos un caso de herencia de una clase concreta, y cómo las subclases heredan los métodos de su
superclase. Por último aprendimos a usar super: cuando una subclase lo envía, se evalúa el método del mismo
nombre de su superclase.
function sumatoriaLetrasDePalabrasCortas (array){

menoraseis=array.select{|elemento|elemento.length<=6}
return menoraseis.sum{solucion.js:3
menoraseis=array.select{|elemento|elemento.length<=6}
^

SyntaxError: Unexpected token {

|elemento| elemento.length}

class Banda
def initialize(integrantes)
@integrantes = integrantes
end

def tocar!
@integrantes.each{|integrante|integrante.tocar!}
end
end

class Bajista
def initialize(cuerdas)
@cuerdas = cuerdas
end
def tocar!
@cuerdas=@cuerdas -1
end
def cuerdas
@cuerdas
end
end

class Baterista
def initialize(indice_de_coordinacion)
@indice_de_coordinacion = indice_de_coordinacion
end
def tocar!
@indice_de_coordinacion = @indice_de_coordinacion +38
end

def indice_de_coordinacion
@indice_de_coordinacion
end

end
class Triangulista
def tocar!
end

end

También podría gustarte