Ruby - Argentina Programa
Ruby - Argentina Programa
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.
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 @
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.
Ejemplo 1: 5.+ 6
Ejemplo 2: 3.< 27
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.
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"
...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?
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).
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:
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:
¿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:
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:
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.
... 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
module Fito
@felicidad = 100
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;
module AbuelaClotilde
def self.alimentar_nieto!
Fito.comer! 2000
Fito.comer! 1000
end
end
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…
...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.
module Pepita
@energia = 100
def self.volar_en_circulos!
@energia -= 10
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.
@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
module Iruya
end
...si bien:
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)
.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.
.each hace que cada objeto de la colección ejecute la funcion que se le pasa al bloque
.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):
Ejemplo:
Dada una lista determinada con la siguiente información: numeros_aleatorios = [ 1,27,8,7,8,27,87,1 ]
.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.
un_numero = 7
incrementador = proc { un_numero = un_numero + 1 }
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 (
,):
Ejemplo:
un_numero = 3
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.
module CelularDeMaría
@saldo = 25
def self.realizar_llamada!
@saldo -= 5
end
def self.cargar_saldo!(pesos)
@saldo += pesos
end
end
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.
todas las clases, entiende el mensaje .new, que crea una nueva instancia de esa clase.
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.
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
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.
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.
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.
class Saludo
def saludar
"Buen día"
End
end
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}
^
|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