Diferencia entre revisiones de «Programación en Ruby»

Contenido eliminado Contenido añadido
Línea 395:
=='''Estructuras de Decisión e Iteración '''==
=='''Declaración, definición y uso de Métodos y Funciones '''==
=='''Implementación y uso de la Programación Orientada a Objetos '''==
Estructuras Simples
En Ruby, sólo nil y false son evaluados como falso, todo lo demás (incluyendo 0), es verdadero. En Ruby nil es un objeto. Puedes agregar métodos a nil como a cualquier otro objeto y puedes llamar los métodos de nil como los de cualquier otro objeto.
Vamos a explorar algunas estructuras muy simples disponibles en Ruby. El ejemplo que sigue (p014estructuras.rb) muestra la estructura if else end. Es costumbre en ruby no poner paréntesis con if y while.
1 #En Ruby, ninl y flase son evaluados como falso
2 #todo lo demas (incluyendo 0) es verdadero.
3 # nil es un objeto
4 # if else end
5 var = 5
6 if var > 4
7 puts "La variable es mayor que 4"
8 puts "Puedo tener muchas declaraciones aqui"
9 if var == 5
10 puts "Es posible tener if y else anidados"
11 else
12 puts "Too cool"
13 end
14 else
15 puts "La variable no es mayor que 4"
16 puts "Puedo tener muchas declaraciones aqui"
17 end
18
19 # Loops
20 var = 0
21 while var < 10
22 puts var.to_s
23 var += 1
24 end
 
'''Un ejemplo del uso de elsif está en el programa p015elsif.rb :'''
 
1 # ejemplo del uso de elseif
2
3 # Ejemplo original
4 puts "Hola, cual es tu nombre?"
5 STDOUT.flush
6 nombre = gets.chomp
7 puts 'Hola, ' + nombre + '.'
8
9 if nombre == 'Juan'
10 puts 'Que bonito nombre!!'
11 else
12 if nombre == 'Ivan'
13 puts 'Ivan es Juan en ruso!!'
14 end
15 end
16
17 # Ejemplo modificado usando elsif
18 puts "Hola, cual es tu nombre?"
19 STDOUT.flush
20 nombre = gets.chomp
21 puts 'Hola, ' + nombre + '.'
22
23 if nombre == 'Juan'
24 puts 'Que bonito nombre!!'
25 elsif nombre == 'Ivan'
26 puts 'Ivan es Juan en ruso!!'
27 end
28
29 # Otra modificacion
30 puts "Hola, cual es tu nombre?"
31 STDOUT.flush
32 nombre = gets.chomp
33 puts 'Hola, ' + nombre + '.'
34
35 # || es el operador logico 'o'
36 if nombre == 'Juan' || nombre == 'Ivan'
37 puts 'Que bonito nombre!!'
38 end
 
Algunos operadores condicionales comunes son: ==, != <=, >=, <, >
Ruby tiene también una forma negativa de if. La estructura unless comienza con la palabra unless y termina con end. El cuerpo es el texto que aparece en medio de las dos. A menos que la expresión que continúe a la palabra unless sea verdadera, el cuerpo es ejecutado, de lo contrario el intérprete lo ignora.
1 unless ARGV.length == 2
2 puts "Usage: program.rb 23 45"
3 exit
4 end
 
En el programa anterior, el cuerpo es ejecutado a menos que el número de elementos en el array sea igual a 2. El método Kernel.exit termina el programa, regresando un valor de status al sistema operativo.
Loops como while están disponibles. Observa el siguiente ejemplo:
 
1 #Loops
2
3 var = 0
4 while var < 10
5 puts var.to_s
6 var += 1
7 end
 
'''Tarea:'''
 
1.Escribe un programa (p016bisiesto.rb) que pregunte al usuario un año cualquiera y determine si es bisiesto o no.
2.Escribe un método llamado bisiesto que acepte un año, determine si es bisiesto y calcule el número total de minutos para ese año. (p017metodobisiesto)
 
Para determinar si un año es bisiesto:
1.Si el año es divisible ente 4, ve al paso 2. Si no, ve al paso 5.
2.Si el año es divisible ente 100, ve al paso 4. Si no, ve al paso 5.
3.Si el año es divisible ente 400, ve al paso 4. Si no, ve al paso 5.
4.El año es bisiesto. (Tiene 365 días).
5.El año no es bisiesto. (Tiene 365 días).
 
=='''Expresiones case'''==
Esta estructura funciona de manera muy similar a una serie de expresiones if: te permite enumerar una serie de condiciones y ejecutar una expresión que corresponda al primer valor que sea verdadero. Por ejemplo, los años bisiestos deben ser divisibles entre 400 o entre 4 y no entre 100. Ten presente que case regresa el valor de la última expresión ejecutada.
1 year = 2000
2
3 leap = case
4 when year % 400 == 0: true
5 when year % 100 == 0: false
6 else year % 4 == 0
7 end
8
9 puts leap
10
11 #el resultado es: true
 
 
 
 
 
'''Escribiendo nuestras propias clases'''
 
Hasta ahora hemos usado el estilo de programación procedural (que todavía se utiliza en lenguajes como C) para escribir nuestros programas. Programar de manera procedural significa que nos enfocamos en los pasos necesarios para completar la tarea sin prestar atención a cómo son manipulados los datos.
 
En el estilo de programación Orientado a objetos, los objetos son tus agentes, tus proxies, en el universo de tu programa. Tu les pides información, les asignas tareas, les pides que realicen cálculos y te los reporten y los comunicas entre si para que trabajen juntos.
Cuando diseñes una clase, piensa en los objetos que van a ser creados de ella. Piensa acerca de lo que los objetos conocen y las cosas que hacen.
 
Las cosas que un objeto sabe de si mismo se llaman variables de instancia (instance variables). Representan el estado de un objeto (los datos, por ejemplo, la cantidad y el id de un producto) y pueden existir valores únicos para cada instancia de la clase.
Las cosas que un objeto puede hacer se llaman métodos.
Un objeto es una entidad que sirve como contenedor de datos y también controla el acceso a los mismos. Asociados con el objeto, hay una serie de atributos que esencialmente no son más que variables que le pertenecen al objeto. También asociadas con el objeto, hay una serie de funciones que proveen una interface para la funcionalidad del objeto, llamadas métodos. Hal Fulton
Una clase es una combinación de estado y métodos y es utilizada para construir objetos. Es una especie de plano para un objeto. Por ejemplo, es posible que utilices una clase llamada Boton para hacer decenas de botones diferentes y cada uno puede tener su propio color, tamaño, forma, etiqueta, etc. Un objeto es una instancia de una clase.
 
'''Lee esto con atención!'''
 
Las clases en ruby son objetos de primera clase, cada una es una instancia de la clase Class. Cuando una nueva clase es definida (de manera típica usando class Nombre end), un objeto de clase Class es creado y asignado a una constante (Nombre en este caso). Cuando llamamos Nombre.new para crear un objeto, el método de instancia en la clase Class es llamado, que a su vez llama al método allocate que asigna memoria para el objeto antes de finalmente llamar el método initialize. Las fases de construcción e inicialización de un objeto son independientes y ambas pueden ser sobreescritas. La inicializacón se hace mediante el método de instancia initialize mientras que la construcción se hace vía el método de clase new. initialize no es un constructor!.
La siguiente Jerarquía de clases es informativa.
Vamos a escribir nuestra primera clase simple. p029perro.rb
 
1 # definicion de la clase Perro
2 class Perro
3 def initialize(raza, nombre)
4 # Variables de instancia
5 @raza = raza
6 @nombre = nombre
7 end
8
9 def ladra
10 puts 'Ruff! Ruff!'
11 end
12
13 def muestra
14 puts "Soy de raza #{@raza} y mi nombre es #{@nombre}"
15 end
16 end
17
18 # Crear un objeto
19 # Los objetos son creados en el 'heap'
20 p = Perro.new('Labrador', 'Benzy')
21
22 =begin
23 Cada objeto 'nace' con ciertas abilidades innatas.
24 Para ver una lista de los métodos con los que nace un objeto
25 puedes llamar el metodo methods
26 =end
27 puts p.methods.sort
28
29 # Entre todos estos metodos, oject_id y respond_to? son
30 # importantes. Cada objeto en ruby tiene asociado un numero
31 # unico.
32 puts "El id del objeto es #{p.object_id}."
33
34 # Para saber si un objeto sabe como responder a un mensaje
35 # puedes usar el metodo respond_to?
36 if p.respond_to?('habla')
37 p.habla
38 else
39 puts 'Lo siento, el objeto no entiende el mensaje habla.'
40 end
41
42 p.ladra
43 p.muestra
44
45 # hacer que d y d1 hagan referencia al mismo objeto
46 p1 = p
47 p1.muestra
48
49 # hacer que d haga referencia a nil
50 p = nil
51
52
53 # Si ahora declaramos:
54 p1 = nil
55 # entonces el Objeto de clase perro es abandonado y es
56 # elegible para la recoleccion de basura (GC)
 
Si ejecutamos el programa, además de la lista de métodos con los que nace el objeto 1, obtenemos como resultado:
 
<gallery>
Archivo:1.JPG
</gallery>
 
El método new es usado para crear un objeto de clase Perro. Los objetos son creados en el heap. La variable p es conocida como una variable de referencia. No guarda el objeto en si, sino algo parecido a un apuntador o una dirección del objeto. Utilizamos el operador punto (.) en una variable de referencia para decir, "utiliza lo que está antes del punto para traerme lo que está después del punto". Por ejemplo: p.ladra.
 
Si estás escribiendo una aplicación Rails en la que uno de tus modelos es, digamos, Cliente, entonces cuando escribes el código que hace que las cosas pasen (un cliente accesando un sitio, actualizando un número de teléfono de un cliente, agregando un artículo a un carrito de compras), con toda seguridad estarás enviando mensajes a objetos de la clase Cliente.
Aún recién creado, un objeto no está completamente en blanco. Tan pronto como un objeto comienza a existir, responde a algunos mensajes. Cada objeto 'nace' con ciertas habilidades innatas. Para ver una lista de los métodos con los que nace un objeto, puedes usar el método methods.
 
Es posible determinar de antemano (antes de pedirle a un objeto que haga algo) si un objeto es capaz de manejar determinado mensaje usando el método respond_to?. Este método existe para todos los objetos; puedes preguntarle a cualquier objeto si responde a cualquier mensaje. respond_to? aparece usualmente en conexión con la condicion lógica if.
 
1 class Perro
2 def initialize(raza, nombre)
3 @raza = raza
4 @nombre = nombre
5 end
6 end
7
8 p = Perro.new('Alsacian', 'Lassie')
9 puts p.class.to_s
 
'''El resultado es: '''
<gallery>
Archivo:2.JPG
</gallery>
instance_of? regresa true si el objeto es instancia de la clase especificada.
 
1 num = 10
2 puts (num.instance_of? Fixnum) # true
 
==Constructores Literales==
 
Esto significa que puedes usar notación especial en lugar de llamar new para crear objetos de una clase determinada. Las clases con constructores literales se muestran en nla siguiente tabla. Cuando usas uno de estos constructores literales, estas creando un nuevo objeto:
 
Clase Constructor Ejemplo
String "" "nueva cadena" o 'nueva cadena'
Symbol : :simbolo o :"simbolo con espacios"
Array [] [1,2,3,4,5]
Hash {} {"Nueva York" => "NY", "Oregon" => "OR"}
Range .. o ... 0...10 o 0..9
Regexp // /([a-z]+)/
==Recolección de basura==
 
La expresión p = nil significa que no hace referencia a nada. Si ahora escribimos p1 = nil, entonces el objeto Perro es abandonado y es elegible para la recolección de basura. Garbage Collection (GC). En Ruby, el objeto llamado heap destina un mínimo de 8MB. El recolector de basura de Ruby es del tipo llamado mark-and-sweep. Ruby usa un mecanismo conservador del tipo mark and sweep. No hay garantía de que un objeto sea recolectado antes de que el programa termine.
 
'''Métodos de clase'''
 
Un método de clase es enviado es enviado a la clase misma, no a una instancia de la clase. Algunas operaciones que pertenecen a la clase no pueden ser llevadas a cabo por instancias individuales de esa clase. new es un ejemplo excelente.
 
 
Llamamos Perro.new porque, hasta que hayamos creado una instancia de clase Perro no podemos enviarle mensajes! Además, el trabajo de crear un nuevo objeto lógicamente pertenece a la clase. No tiene sentido que una instancia de la clase Perro cree a su vez instancias de su misma clase. Sin embargo, si tiene sentido que el proceso de creación de instancias se centralizado como una actividad de la clase Perro. Es de vital importancia entender que Dig.new es un método que podemos accessar a través de la clase pero ne de las instancias de la clase.
 
Los objetos individuales "Perro" (instancias de la clase Perro) no tienen acceso a este método. Una clase tiene sus propios métodos, su propio estado y su propia identidad y no los comparte con sus instancias.
 
La siguiente tabla muestra un ejemplo (tomado del libru Ruby for Rails) de la notación que se utiliza:
 
Notación Se refiere a
Boleto#precio El método de instancia precio de la clase Boleto
Boleto.mas_caro El método de clase mas_caro de la clase Boleto
Boleto::mas_caro Otra manera de referirse al método de clase mas_caro
 
Cuando escribimos acerca de Ruby, el símbolo de número(#) es utilizado algunas veces para indicar en método de instancia -por ejemplo, decimos File.chmod para denotar el método de clase chmod de la clase File y File#chmod para referirnos al método de instancia que tiene el mismo nombre. Esta notación no es parte dela sintaxis de Ruby, es sólo parte del folklore.
==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:
<gallery>
Archivo:3.jpg
</gallery>
'''¿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).  '''
 
 
==Herencia==
 
En ruby, la herencia se maneja herencia, pero no soporta multiple herencia,
por lo que cada clase solo puede tener una superclase de la que herede comportamintos.
 
la sintaxis es la siguiente:
 
class ClasePadre
def a_method
puts 'b'
end
end
class ClaseCualquiera < ClasePadre
# < significa hereda
def another_method
puts 'a'
end
end
 
en esta sentencia se declara una ClasePadre,con un método, luego ClaseCualquiera, hija de ClasePadre
con otro método, si hacemos lo siguiente:
instance = SomeClass.new
instance.another_method
instance.a_method
 
Salida
 
a
b
 
 
vemos que se aplica la herencia de métodos correctamente al llamar desde una instancia hija un método
de la clase padre
 
'''Polimorfismo'''
 
Si queremos redefinir un método de la clase padre en la hija, solo sobrescribimos el método
que deseamos redefinir en la clase hija, de esta manera, dependiendo de el tipo de la instancia
desde la cual llamamos al método, se utilizará la correspondiente definición
 
 
 
Ademas, para llamar a la clase padre en cualquier momento desde un hija
utilizamos la palabra reservada super, sin embargo, si quieres acceder a un clase superior a el padre
en la jerarquía de herencia(como un abuelo, digamos), no se puede directamente, sin embargo hay una salida
puedes darles nombre afiliados a los métodos que deseas usar luego, como un alias!, de hecho es exactamente esto,
veamos
 
class X
def foo
"hello"
end
end
class Y < X
alias xFoo foo
def foo
xFoo + "y"
end
end
puts X.new.foo
puts Y.new.foo
 
Salida
 
hello
helloy
 
=='''Esquema de administración y separación de la Memoria '''==
=='''Implementación de Co-Rutinas '''==