Laura P. Cerón Martinez y Camilo A. Dajer Piñerez
Universidad Nacional de Colombia
Lenguajes de programación 2017-II
Toda su documentación puede ser encontrada aquí
Todo en Ruby es considerado un objeto, inclusive nil.
Los comentarios en Ruby se realizan de dos maneras:
puts 2**(5%3)
4
En Ruby se poseen dos metodos para la impresión en consola.
Ruby permite el manejo de Strings de manera sencilla, estas pueden estar entre comillas dobles *"Cadena"* o en comillas sencillas *'Cadena'*. Sin embargo su uso es diferente:
Las cadenas que se encuentren entre comillas dobles permiten de la presencia embebida de caracteres de escape precedidos por un backslash y la expresión de evaluación #{ }, por ejemplo:
puts "Lenguajes\nde\nprogramación"
Lenguajes de programación
a = 'ejemplo'
puts "a\n#{a}\nb\nc"
a ejemplo b c
Sin embargo si se declarara en comillas simples:
a = 'ejemplo'
puts 'a\n#{a}\nb\nc'
a\n#{a}\nb\nc
La concatenación en Ruby es muy sencilla, se realiza a través del operador +. Adicionalmente se puede concatenar una palabra consigo mismo una cantidad de veces determinada de la siguiente manera:
puts 'HolaMundo' * 5
HolaMundoHolaMundoHolaMundoHolaMundoHolaMundo
Se realiza de la misma manera que en python, sin embargo si se poseen indices negativos empezara desde el final de la cadena.
palabra = "Lenguajes"
puts palabra[-2,2]
es
Debido a que todo en Ruby es tratado como un objeto, el casting se realizar mediante el llamado del objeto como veremos a continuación:
ejemplo1 = 1.to_s
puts ejemplo1.class #String
ejemplo2 = "10000".to_i
puts ejemplo2.class #Numero => Fixnum
String Fixnum
Los tipos de casting son:
[[:llave1, :llave2], ["valor1", "valor2"]].to_h
{:llave1=>:llave2, "valor1"=>"valor2"}
Las listas se pueden crear listando elementos entre corchetes y separando cada elemento por comas. Estas listas pueden almacenar objetos de distintas clases sin restricción.
La manera de concatenar listas es igual a como se realiza con cadenas, usando el operador +.
Para adicionar elementos a una lista se puede hacer uso de la función .push o haciendo uso del operador **<<
visitar = ["Brasil", "Italia", "Egipto" ]
visitar.push("Turquia")
puts visitar
visitar << "Japon"
puts visitar
["Brasil", "Italia", "Egipto", "Turquia"] ["Brasil", "Italia", "Egipto", "Turquia", "Japon"]
Las listas se pueden convertir a y obtener de cadenas con los métodos join y split respectivamente.
array_1 = [1,2,3]
array_2 = "456"
puts array_1 + array_2.split('')
[1, 2, 3, "4", "5", "6"]
array_3 = ['H','o','l','a']
puts array_3.join + " mundo"
Hola mundo
El operador map nos permite recorrer cada elemento de la lista y realizar una operación en él, es parecido a un iterador pero eso lo estudiaremos mas adelante.
arreglo = [1, 2, 3]
puts arreglo.map { |n| n * n } #=> [1, 4, 9]
[1, 4, 9]
En Ruby a los diccionarios se les denomina hash. Al igual que en Python, estan compuestos por llaves y valores.
La manera de declarar un hash y acceder a un valor con su llave es la siguiente:
dict = {1 => "Lunes", "6" => "Sabado", 7 => " "}
dict[7] = dict["6"] + " y Domingo"
dict[3] = "Miercoles" # agregamos una nueva llave
puts dict
{1=>"Lunes", "6"=>"Sabado", 7=>"Sabado y Domingo", 3=>"Miercoles"}
Ruby permite implementar rangos de una manera muy sencilla:
range = (46..65).to_a
puts range
[46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65]
Si no se desea incluir el ultimo numero se deben colocar ...
range = (46...65).to_a
puts range
[46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64]
Los símbolos son el objeto mas básico de Ruby, estos son útiles por que dado un símbolo, se refiere al mismo objeto en todo el programa. Por esta razón son más eficientes que las cadenas: dos strings con el mismo nombre, son dos objetos distintos. Esto implica un ahorro de tiempo y memoria.
puts "cadena".object_id
puts "cadena".object_id
puts :cadena.object_id
puts :cadena.object_id
40163604 40162272 2151764 2151764
Los métodos que terminan en ! son aquellos que modificaran de manera definitiva al objeto, una manera sencilla de ver su comportamiento es el siguiente:
arreglo = [4,3,2,1]
puts arreglo.sort
puts arreglo #El arreglo no fue modificado e imprimira [4,3,2,1]
puts arreglo.sort!
puts arreglo #El arreglo fue modificado e imprimira [1, 2, 3, 4]
[1, 2, 3, 4] [4, 3, 2, 1] [1, 2, 3, 4] [1, 2, 3, 4]
Su funcionamiento y declaración es la misma que la de python.
i = 30**(2%4)
if i < 10
puts "Es menor a 10"
elsif i == 20
puts "Es 20"
else
puts "No es ninguna de las anteriores"
end
No es ninguna de las anteriores
La manera de implementar un while es muy similar a C, como se puede observar a continuación.
i = 0
while( i < 3 )
puts i
i += 1
end
0 1 2
Sin embargo se poseen 4 palabras reservadas para hacer operaciones especiales en el bucle:
k = 26
while( k > 10 )
if (k % 12 == 0)
k-=1
puts "Ejecute un next"
next
elsif (k% 7 == 0 )
k-= 1
puts "Ejecute un break"
break
else
k-=1
puts k
end
puts "Iteracion # "+ k.to_s
end
25 Iteracion # 25 24 Iteracion # 24 Ejecute un next 22 Iteracion # 22 21 Iteracion # 21 Ejecute un break
Tambien Ruby posee la estructura de control until, que funciona de manera similar a la negación de la condición del while.
La sentencia case es usada para comprobar un valor, su funcionamiento es similar a un switch de Java.
valor = 30
case valor
when 30, (1..10)
puts "1 - 10" + ", o puede ser 30"
when 11..20
puts "11 - 20"
end
1 - 10, o puede ser 30
Se pueden recorrer colecciones de manera compacta y sencilla, ejecutandose una vez por cada de elemento de la colección:
random_string = ["Hola ","2 ","soy ","el ","5"]
for r in random_string
print r
end
Hola 2 soy el 5
["Hola ", "2 ", "soy ", "el ", "5"]
De manera similar se puede realizar un for en un rango determinado de la siguiente manera:
for i in (0..10)
puts (i*7 + i) % 3
end
0 2 1 0 2 1 0 2 1 0 2
0..10
Los iteradores nos permiten una accion repetidas veces, parecido a un ciclo, sin embargo su codificación es diferente.
Las cadenas en Ruby tienen iteradores que puede ser útiles, entre los cuales encontramos:
Permite iterar a través de cada letra de la cadena.
"cadena".each_byte{|letra| puts letra.chr}
c a d e n a
"cadena"
Permite iterar a través de cada linea de la cadena.
"Esto\nes\nuna\nfrase".each_line{|linea| print linea}
Esto es una frase
"Esto\nes\nuna\nfrase"
Funciona de manera similar al for para recorrer elementos de una lista.
[1,2,3,4].each do |f|
puts f
end
1 2 3 4
[1, 2, 3, 4]
a = [1,2,3,4,5]
b = a.collect{|x| 10*x}
puts b
[10, 20, 30, 40, 50]
Este comando crea una copia nueva de un arreglo la cual sera guardada en un espacio de memoria diferente con lo cual se evita sobreescribir el arreglo original
mes = ["Enero","Febrero","Marzo"]
los_mismos_meses = mes
otros_meses = mes.clone
otros_meses.push("Abril")
puts "Meses" + mes.to_s
puts "Mismos meses" + los_mismos_meses.to_s
puts "Otros meses" + otros_meses.to_s
Meses["Enero", "Febrero", "Marzo"] Mismos meses["Enero", "Febrero", "Marzo"] Otros meses["Enero", "Febrero", "Marzo", "Abril"]
Ruby es un lenguaje orientado a objetos, como pudimos observar en las explicación anterior, todo en ruby es un objeto.
Un método de un objeto en Ruby es muy sencillo de usar, solo se debe colocar la instancia de la clase con un . y el nombre del método del objeto a llamar, con sus respectivos parametros que deben ir en paréntesis.
Algunos métodos predefinidos de los objetos en Ruby son:
La manera de definir un método es la siguiente:
def nombreDelMetodo
#Comandos
end
Sin embargo, en caso de recibir paramétros estos deben ir entre paréntesis, separados por comas sin especificar el tipo:
def nombreDelMetodo(a,b)
#Comandos
end
Ruby no permite una manera convencional de realizar polimorfismo, para poder realizarlo se debe realizar de la siguiente manera:
def operaciones(*args) # * implica número variable de argumentos
num_args = args.size
if args.size > 4
puts 'ERROR: Numero excesivo de argumentos'
else
case num_args
when 2
puts "Multiplique 2 numeros: " + (args[0]*args[1]).to_s
when 3
puts "Modulo: "+ args[2].to_s + " de la suma de 2 numeros: " +((args[0]+args[1]) % args[2]).to_s
when 1
puts"Solo entro el numero: " + args[0].to_s
end
end
end
operaciones(9,24,8)
Modulo: 8 de la suma de 2 numeros: 1
Este método nos permite saber si una variable a sido declarado y en dado nos devuelve una descripción de la variable.
var1 = 1
@var2 = 1
$var3 = 1
Var4 = 1
puts defined? var1
puts defined? Var4
local-variable constant
Las clases en Ruby son muy fáciles de declarar, su estructura es muy similar a la de Python, por lo cual nos permite declarar atributos y metodos a una clase de manera intuitiva e interactuar con ellos.
La estructura de una clase en Ruby es la siguiente:
# Definimos la clase Persona
class Pais
# Constructor de la clase
def initialize(nombre,continente,idioma)
# atributos
@nombre = nombre
@continente = continente
@idioma = idioma
end
# método saludar
def ubicacion
puts "Hola! mi nombre es #{@nombre} y me encuentro en #{@continente}"
end
def lenguaje
puts "En #{@nombre} se habla #{ @idioma} "
end
end
colombia = Pais.new("Colombia","América", "Español")
colombia.ubicacion
colombia.lenguaje
Hola! mi nombre es Colombia y me encuentro en América En Colombia se habla Español
Las variables definidas con @ son consideradas como los atributos de la clases y estos pueden accedidos desde cualquier método de la clase.
Para poder implementar herencia en nuestro código solo debemos hacer uso del caracter < en la definición de la clase, de esta manera extenderemos de la clase declarada a la derecha del operador.
class Vehiculo
def transportar
puts "Me movilizo"
end
end
class Avion<Vehiculo
def volar
puts "Los aviones volamos"
end
def aterrizar
puts "Los aviones aterrizamos"
end
end
Avion.new.volar
Los aviones volamos
Sin embargo hay casos en los que una subclase no deberia heredar el comportamiento de la clase padre por lo que es posible reescribir el método en la subclase.
class VehiculoTerrestre
def neumaticos
puts "Tengo 4 neumaticos"
end
end
class Tractomula<VehiculoTerrestre
def neumaticos
puts "Tengo 22 neumaticos"
end
end
Tractomula.new.neumaticos
Tengo 22 neumaticos
Ruby permite hacer uso de la palabra reservada super, que permite ejecutar el código del método definido en el padre y adicionalmente ejecutar el método definido en la subclase.
Ruby nos permite aplicar encapsulamiento a métodos de nuestra clase declarando la palabra private y el nombre de la clase como simbolo.
class Cuenta
def initialize(ahorro,clave)
@ahorro = ahorro
@clave = clave
end
def balance(clave)
if clave == @clave
return getAhorro
else
return "No autorizado"
end
end
def getAhorro
return @ahorro
end
private :getAhorro
end
a = Cuenta.new(1000,1234)
puts a.balance(1234)
1000
Algunas veces es necesario modificar el comportamiento de un método de algun objeto en particular, lo que nos implicaria tener que crear una nueva clase para ese objeto. Ruby nos permite modificar el comportamiento de los objetos de manera individual.
class Estudiante
def admision
#Operaciones
return "Regular"
end
end
estudiante_1 = Estudiante.new
estudiante_2 = Estudiante.new
estudiante_3 = Estudiante.new
estudiante_4 = Estudiante.new
def estudiante_4.admision
#Nuevas operaciones
return "PEAMA"
end
puts estudiante_1.admision
puts estudiante_2.admision
puts estudiante_3.admision
puts estudiante_4.admision
Regular Regular Regular PEAMA
Ruby distintas clases de variables, las cuales se especifican de la siguiente manera:
En Ruby no se permite el acceso a los atributos de una instanacia de manera directa como lo permite Java, este proceso se debe realizar mediante métodos definidos en la clase. Sin embargo Ruby no permite definir un método para acoplarnos a esa sintaxis:
class Factura
def initialize(valor)
@valor = valor
end
def valor=(valor)
@valor = valor
end
def valor
return @valor
end
end
f1 = Factura.new(10000)
#Modificación del atributo valor
f1.valor = 20000
puts f1.valor
20000
Sin embargo Ruby sabe que esto lo hacen la mayoria de programadores, para no tener que repitir los getters y setters por cada atributo podemos hacer lo siguiente:
class Factura
attr_accessor :valor #, mas atributos
def initialize(valor)
@valor = valor
end
end
f2 = Factura.new(10000)
#Modificación del atributo valor
f2.valor = 30000
puts f2.valor
30000
Es una estructura de datos muy interesante, permite a su instancia la declaracion arbitraria de atributos. Su uso es parecido a un hash.
require "ostruct"
person = OpenStruct.new
person.name = "Nombre"
person.age = 50
puts person.name # => "John Smith"
puts person.age # => 70
puts person.address # => nil
Nombre 50
class Producto
attr_accessor :nombre
attr_accessor :caract
attr_accessor :valor
attr_accessor :fabricante
def initialize(nombre,caract,valor, fabricante)
@nombre= nombre
@caract = caract
@valor = valor
@fabricante = fabricante
end
def descripcion
print "Nombre: #{@nombre}"
print "\nCaracteristicas:\n"
@caract.each do |c|
puts "\t" + c.to_s
end
"Valor: $#{@valor}\nFabricante: #{@fabricante}"
.each_line{|l| print l}
end
end
p = Producto.new("Producto1",["Grande","Pesado","Elegante"],2000,"X")
p.descripcion
Nombre: Producto1 Caracteristicas: Grande Pesado Elegante Valor: $2000 Fabricante: X
"Valor: $2000\nFabricante: X"
class Electrodomestico<Producto
attr_accessor :garantia
def initialize(nombre,caract,valor,fabricante,garantia)
super(nombre,caract,valor,fabricante)
@garantia = garantia
end
def descripcion
print "Nombre: #{@nombre}"
print "\nCaracteristicas:\n"
@caract.each do |c|
puts "\t" + c.to_s
end
"Valor: $#{@valor}\nFabricante: #{@fabricante}\nGarantia: #{@garantia}"
.each_line{|l| print l}
end
end
e = Electrodomestico.new("Portátil ASUS ROGGL552 i5 15",
["Procesador: Intel® Core i5","Sistema Operativo:Windows 10","Memoria: 8GB","Disco Duro: 1TB","Pantalla: 15.6"],
2899000,"ASUS","1 año")
e.descripcion
Nombre: Portátil ASUS ROGGL552 i5 15 Caracteristicas: Procesador: Intel® Core i5 Sistema Operativo:Windows 10 Memoria: 8GB Disco Duro: 1TB Pantalla: 15.6 Valor: $2899000 Fabricante: ASUS Garantia: 1 año
"Valor: $2899000\nFabricante: ASUS\nGarantia: 1 año"
class Pago
def pagar(*args)
num_args = args.size
if args.size == 0
puts 'ERROR: FALTAN PRODUCTOS '
elsif num_args == 1
return args[0].valor
elsif num_args >1 and num_args <4
b = 0
args.each do |a|
b+= a.valor
end
return b * 0.70
else
b = 0
args.each do |a|
b+= a.valor
end
return b * 0.50
end
end
end
p = Producto.new("Producto1",["Grande","Pesado","Elegante"],2000,"X")
p1 = Producto.new("Producto2",["Grande","Pesado","Elegante"],3000,"X")
p2 = Producto.new("Producto3",["Grande","Pesado","Elegante"],4000,"X")
p3= Producto.new("Producto4",["Grande","Pesado","Elegante"],5000,"X")
checkout = Pago.new
puts checkout.descuento(p1,p2,p3,p)
7000.0