RUBY
Lenguaje Ruby
• Ruby es un lenguaje de programación
orientado a objetos puro.
• Fue creado en Japón a principios de los
noventa.
• Ruby consiste en mensajes enviados a
objetos.
Introducción a objetos y llamadas a
métodos
• Una llamada a un métodos puede consistir en el nombre
del método seguido de uno ó más argumentos. Por
ejemplo, llamamos al método puts con un argumento:
puts “Hola”
• Otros métodos usan una sintaxis especial: un operador
punto, que establece una relación entre un valor o
expresión del lado izquierdo y un método del lado
derecho, por ejemplo:
x = “100”.to_i el punto significa que el mensaje “to_i”
está siendo enviado a la cadena “100” y se conoce como el
receptor del mensaje, es un objeto.
• El siguiente ejemplo utiliza la notación del punto y
también toma un argumento. En éste se genera un
entero decimal equivalente a base 9.
x = “100”.to_i(9) los paréntesis son opcionales, pero son
convenientes. La x ahora vale 81.
Escribiendo y salvando un
programa
[tinestri@cadit ~]$ cd public_html/
[tinestri@cadit ~]$ mkdir ruby_pruebas
[tinestri@cadit ~]$ cd ruby_pruebas
[tinestri@cadit ruby_pruebas]$ jed c2f.rb
Se puede utilizar cualquier editor de textos
(vi, jed, etc). Vamos a crear un programa
llamado c2f.rb para convertir de grados
Celsius a Fahrenheit.
c = 100
f = (c * 9 / 5) + 32
puts "El resultado es:
"
puts f
puts "."
[tinestri@cadit ruby_pruebas]$ ruby -cw c2f.rb
Syntax OK
En –cw, c significa que cheque errores de sintaxis,
-w activa un nivel más alto de warning, aún si es
legal en Ruby puede ser que sea cuestionable
por una cosa o la otra.
• Para correr el programa pasamos el
archivo al intérprete pero esta vez sin las
banderas –c y –w:
[tinestri@cadit ruby_pruebas]$ ruby c2f.rb
El resultado es:
212
.
• ¿Cómo podemos modificarlo para que
salga en una misma línea?
usar print
Entrada desde el teclado
Para que el programa anterior solicite los grados para
convertirlos deberá utilizar los siguientes métodos:
gets (get string) detiene el programa y espera una línea de
entrada desde el teclado.
to_i (to integer) convierte una cadena a un entero, éste
servirá para que la cadena que se teclee esté de acuerdo
con los otros números cuando se calculen los grados
Fahrenheit. [tinestri@cadit ruby_pruebas]$ ruby c2fi.rb
puts "Teclea los grados Celsius"
c = gets
f = (c * 9 / 5) + 32
print "La equivalencia en Fahrenheit es
"
print f
puts "."
Entrada desde archivos
Primero hay que crear un archivo llamado
temp.data, que contenga una sola línea
con un solo número, por ejemplo: 100
[tinestri@cadit ruby_pruebas]$ ruby c2fin.rb
puts "Leyendo los grados desde un
archivo de datos.."
num = File.read("temp.dat")
c = num.to_i
f = (c * 9 / 5) + 32
puts "El numero es: " + num
print "Resultado: "
puts f
Salida hacia archivos
Si queremos escribir en un archivo debemos
utilizar el modo w (write)
[tinestri@cadit ruby_pruebas]$ ruby c2fout.rb
print "Introducir el valor en Celsius"
c = gets.to_i
f = (c * 9 / 5) + 32
puts "El resultado se salva en
'temp.out'"
fh = File.new("temp.out", "w")
fh.puts f
fh.close
Revisar el archivo temp.out para verificar si se
guardó el resultado ahí.
[tinestri@cadit ruby_pruebas]$ jed temp.out
Un programa, múltiples archivos:
require
• Para correrlos como si fueran un solo
programa utilizaremos el método require.
• Ejemplo, crear un archivo reqdemo.rb, en
éste se encuentra un método de llamada
require, a un segundo archivo llamado
requiree.rb.
• Ahora hay que correr en Ruby
reqdemo.rb:
load
La diferencia con require, es la siguiente, si haces
esto:
require “requiree.rb”
require “requiree.rb”
La segunda vez ya no pasa nada; por lo que
usaremos load,
load “requiree.rb”
load “requiree.rb”
Con lo que Ruby lee en el archivo dos veces
seguidas.
irb
Cuando corremos un programa Ruby, en realidad
estamos corriendo un programa llamado ruby al
que alimentamos con nuestro programa.
irb es un intérprete interactivo, que significa que
en lugar de procesar un archivo, procesa lo que
estés tecleando durante una sesión.
Para iniciar una sesión irb, se usa el comando irb.
Y con esto ya se pueden poner comandos Ruby.
Ejemplos
[tinestri@cadit ruby_pruebas]$ irb
irb(main):001:0> 100 * 9 / 5 + 32
=> 212
irb(main):003:0> days = 365
=> 365
irb(main):004:0> horas = 24
=> 24
irb(main):005:0> days * horas
=> 8760
Librerías y extensiones estándar
• Hay una gran cantidad de extensiones y
librerías en Ruby, que ayudan a escribir
programas en diferentes áreas de
especialización. Ruby tiene extensiones para
una gran variedad de proyectos y tareas:
manejo de bases de datos, conectividad,
matemáticas especializadas, procesamiento de
XML, etc.
• Por ejemplo, para usar una extensión se utiliza
require:
require ‘cgi’
Herramientas estándar de Ruby
Debugger, permite correr una instrucción a la vez
del programa, haciendo pausas, en las cuales
puedes examinar el valor de las variables.
Profilling: medir que tanto uso se está dando de
los recursos del sistema.
Rdoc: es un sistema de documentación, que
escanea los archivos, extrae los comentarios y
los organiza.
ERb: Embedded Ruby, permite colocar código de
Ruby dentro de un archivo HTML.
ERb
Erb lee un archivo palabra por palabra (un documento ERb),
despliega la parte de HTML exactamente igual y ejecuta las
instrucciones Ruby que se encuentre.
Los dos puntos importantes son:
– El código Ruby debe colocarse entre .
– Si se quiere imprimir el resultado de la ejecución del código como
parte de la salida, hay que ponerlo entre .
Ejemplo: erbdemo.rb
En este ejemplo hay dos variables: @page_title y @saludo,
las cuales se encuentran dentro de , por lo que
se evalúa el código que corresponde a la asignación que se
hace al principio del programa.
Ejemplo: erbdemo.rb
Es una breve demostracion de como ERb llena un template
Objetos
En cualquier programa Ruby, el diseño, la acción y
la lógica gira alrededor de los objetos.
Primeramente hay que crear objetos y ver que
acciones realizan.
Ruby proporciona un juego completo de
herramientas para nombrar, crear y manipular
objetos.
Si queremos información, se la pedimos a los
objetos, también que lleven a cabo ciertos
cálculos y que nos den el resultado, etc.
Comportamiento de un objeto
Crear un objeto y asignarlo a una variable para poderlo
manipular en el futuro:
[tinestri@cadit ruby_pruebas]$ irb
irb(main):001:0> obj = Object.new
Por ejemplo, si queremos definir un método para que el
objeto obj “hable”, lo llamaremos talk.
irb(main):002:0> def obj.talk
puts “I am an object”
end
Si ejecutamos este código (la definición del código), el
objeto obj no va a “hablar”, más bien le tenemos que
enseñar “como hablar”.
Objeto al que
pertenece el
Operador punto
Método, es el
receptor del
mensaje
Inicio de definición Nombre del
del método método
def obj.talk
puts “I am an object”
end
Cuerpo
Fin de definición del método
del método
Mandando mensajes a los objetos
Para que el objeto hable debemos utilizar un constructor: la
sintaxis de envío de mensajes ó de llamada a un
método. object.message
De acuerdo con este constructor:
• object puede ser una variable, puede ser también una
cadena entre comillas.
• El punto es el operador “message-sending”. El mensaje
de la derecha se manda al objeto de la izquierda.
• En la práctica message es el nombre de un método
(como talk). La idea es que cada mensaje que se
mande a un objeto corresponda a un método que el
objeto pueda llamar.
• Con esta sintaxis ya le podemos pedir al objeto que
“hable”: obj.talk
• Un objeto responde a un mensaje si el objeto tiene un
método definido con ese nombre.
Métodos que toman argumentos
El método puede llamarse con uno ó más argumentos.
En la definición del método, se indican los argumentos como una lista
de variables entre paréntesis después del método.
Cuando se llama al método, se proporcionan valores correspondientes
a las variables en el método.
Ejemplo, supongamos que queremos que el objeto obj funcione como
un convertidor Celsius-to-Fahrenheit, para lo cual crearemos un
método:
irb(main):013:0> def obj.c2f(c)
irb(main):014:1> c * 9 / 5 + 32
irb(main):015:1> end
=> nil
La variable c, es el nombre del argumento de este método y aparece
en la definición del método. Vamos a usar el método para convertir
100, lo pasamos como argumento al método:
irb(main):016:0> puts obj.c2f(100)
Se usó el método puts, para poder ver el resultado del cálculo que
llevó a cabo el método.
El valor de retorno de un método
Una llamada a un método es una expresión. Cuando llamamos a un
método, éste evalúa algo. El resultado de llamar a un método se
conoce como valor de retorno: el valor de retorno de cualquier
método es el valor de la última expresión evaluada durante la
ejecución del método. En el caso del método para la conversión de
temperatura, la última expresión evaluada es la única línea que
tiene el método
c * 9 / 5 + 32
Ruby tiene una forma de hacerlo explícito: return. El uso de esta
palabra clave es opcional:
def obj.c2f(c)
return c * 9 / 5 + 32
end
Clases e Instancias
Todo lo que manejas en Ruby es un objeto y cada objeto es una instancia de una clase.
En el ejemplo: obj = Object.new
obj es una instancia de una clase Object, en este caso estamos mandando un mensaje a la
clase llamada Object. El método new es un constructor, que se encarga de crear y
regresar una nueva instancia de la clase, un objeto nuevo.
Las clases se nombran con un nombre con la primera letra en mayúscula, por ejemplo la
definición de la clase Ticket
irb(main):030:0> class Ticket
irb(main):031:1> def event
irb(main):032:2> "hola"
irb(main):033:2> end
irb(main):034:1> end
=> nil
Ahora ya podemos crear un nuevo objeto ticket y pedirle el método event:
irb(main):035:0> ticket = Ticket.new
=> #
irb(main):036:0> puts ticket.event
hola
=> nil
Instance methods
En el ejemplo anterior método event está definido
en una forma general, lo que significa que se
comparte con todos los tickets (todas las
instancias de la clase Ticket).
Los métodos definidos dentro de una clase y que
pueden usarse por todas las instancias de la
clase, se llaman instance methods. Estos no
pertenecen a un solo objeto.
Los métodos que se definen para un objeto en
particular se conocen como singleton methods
por ejemplo def ticket.price.
Redefiniendo métodos
Podemos definir un método dos veces ó rescribirlo:
irb(main):001:0> class C
irb(main):002:1> def m
irb(main):003:2> puts "Primera definicion metodo m"
irb(main):004:2> end
irb(main):005:1> def m
irb(main):006:2> puts "Segunda definicion metodo m"
irb(main):007:2> end
irb(main):008:1> end
Nil
Que sucede si llamamos al método m en una instancia (objeto) de la clase C:
C.new.m, el resultado será Segunda definición método m ya que
sobrescribimos el método y la nueva versión tiene precedencia.
Reabriendo clases
En la mayoría de las veces cuando defines una clase, se crea un
bloque de definición:
class C
# código de la clase aquí
end
Pero es posible reabrir una clase y hacer adiciones ó cambios a la
misma, por ejemplo si tenemos:
class C
def x
end
end
Podemos aumentar otro método:
class C
def y
end
end
Estado de un objeto
Cuando creamos un objeto (una instancia de
cualquier clase), queremos que tenga
información específica de ese objeto, lo mismo
si creamos uno o más de la misma clase.
La información y los datos asociados con un
objeto en particular se llaman estado del objeto
(state of the object), se debe poder:
- Establecer el estado de un objeto
- Obtener el estado de un objeto
Variables Instancia (instance
variables)
Estas variables permiten a los objetos individuales
recordar su estado.
Trabajan similar a otras variables: les asignas
valores y lees estos valores.
Las diferencias de las variables instancia son:
– Sus nombres siempre inician con @. Lo que permite
reconocerlas fácilmente.
– Solo son visibles al objeto al que pertenecen.
– Una variable instancia inicializada en la definición de
un método, dentro de una clase particular, es la misma
que una variable instancia con el mismo nombre
referenciada en otra definición de método de la misma
clase.
Ejemplo: variable instancia
irb(main):017:0> class C
irb(main):018:1> def inst_var_init(value)
irb(main):019:2> puts "Setting an instance variable"
irb(main):020:2> @ivar=value
irb(main):021:2> end
irb(main):022:1> def inst_var_report
irb(main):023:2> puts "Inspectin the value of the instance variable"
irb(main):024:2> puts @ivar
irb(main):025:2> end
irb(main):026:1> end
Nil
irb(main):027:0> c = C.new
=> #
irb(main):028:0> c.inst_var_init("Solo una prueba")
Setting an instance variable
=> "Solo una prueba"
irb(main):029:0> c.inst_var_report
Inspectin the value of the instance variable
Solo una prueba
=> nil
A diferencia de una variable local, una
variable instancia como @ivar retiene el
valor que se le asignó, aún después de
que el método en la cual fue inicializada
ya finalizó. Esta propiedad de las
variables instancia (sobrevivir a través de
llamadas de métodos) permite que
guarden el estado de un objeto.
Inicializando un objeto con un estado
Cuando creamos por ejemplo la clase Ticket, se puede incluir un método especial
llamado inicialize. Si se define este método, éste será ejecutado cada vez que
se cree una nueva instancia de la clase.
Por ejemplo, si escribimos un método initialize para venue y para date:
class Ticket
def initialize(venue, date)
@venue = venue
@date = date
end
def venue
@venue
end
def date
@date
end
end
Los métodos venue y date, permiten leer las variables venue y date. Esto es, son
métodos que regresan lo que hay en las variables instancia. Los nombres de
las variables instancia, los de los métodos y los de los argumentos de initialize
no tienen que coincidir. Por ejemplo se puede poner @d, en lugar de @date
para recibir el valor que pasa por el argumento date.
Podemos crear uno o varios objetos ticket con juegos de valores para
venue y date para cada ticket, en el ejemplo son th y cc:
th = Ticket.new("Town Hall", "11/12/13")
=> #
cc = Ticket.new("Convention Center", "12/13/14")
=> #
irb(main):078:0> puts "Necesitamos dos tickets, el primero para
#{th.venue} el #{th.date}.. y el segundo para #{cc.venue} el
#{cc.date}.."
Cada ticket tiene su propio estado gracias al método initialize. También
podemos ver la información de cada ticket (venue y date) por los
métodos con esos nombres.
Con esto podemos crear cualquier número de tickets al mismo tiempo,
sin tener que escribir métodos separados para cada uno de éstos.
Todos los tickets comparten los recursos de la clase Ticket y al mismo
tiempo cada ticket tiene su propio juego de variables instancia para
almacenar la información de su estado.
Cambiando el estado de un objeto
En el ejemplo, supongamos que queremos tener una forma de establecer el precio del
ticket, por lo que vamos a escribir el método set_price.
class Ticket
def set_price(amount)
@price = amount
end
def price
@price
end
End
Con esto ya podemos:
irb(main):107:0> th.set_price(65.00)
=> 65.0
irb(main):108:0> th.inspect
"#“
irb(main):112:0> puts "The ticket th costs$#{"%.2f" % th.price}"
El signo (=) en el nombre del método
Hay otra forma de cambiar el estado de un objeto,
vamos a sustituir set_price con un método
llamado price=
class Ticket
def price= (amount)
@price = amount
end
end
price= hace exactamento lo que hacia set_price y
para llamarlo lo hacemos así:
th.price= 65.00
Atributos
Las propiedades o características de los objetos que podemos establecer (escribir) y/o
obtener (get) son atributos. En el caso del objeto ticket podemos decir que cada
ticket tiene un atributo price, uno date y otro venue.
Ruby proporciona técnicas para crear métodos de lectura y escritura para los
atributos.
En el ejemplo del ticket tenemos repetido lo siguiente para cada atributo:
def price
@price
end
Estos métodos se pueden sustituir por la siguiente línea: un método que lee y regresa
el valor de la variable instancia con el mismo nombre que el método:
class Ticket
attr_reader :venue, :date, :price
end
Aquí :venue, :date y :price son simbolos, que son un tipo de facilidad para nombrar o
etiquetar y son funcionalmente equivalentes a strings.
El método att_writer
class Ticket
attr_writer :price
end
Con esta línea Ruby escribe por nosotros el método price=.
Con esto el programa quedaría así:
class Ticket
attr_reader :venue, :date, :price
attr_writer :price
def initialize
@venue = venue
@date = date
end
end
Aquí vemos que el atributo price es reader y writer, para lo cual se
tiene otro método que permite la creación del atributo como de
lectura y escritura
class Ticket
attr_reader :venue, :date
attr_accessor :price
end
attr_reader Crea un attr_reader: def venue
método venue @venue
reader end
attr_writer Crea un attr_writer: def price= (price)
método price @price=price
writer end
attr_accesor Crea un attr_accessor: def price= (price)
método price @price=price
reader y end
writer def price
@price
end
Class methods
Hasta este punto, ya tenemos una visión de los
que son los instance methods: métodos que se
definen dentro de una clase y están disponibles
para todas las instancias de la clase.
Las clases tienen otros tipo de métodos, el class
method. Si analizamos: Ticket.new, estamos
enviando el mensaje new a un objeto llamado
Ticket, que sabemos que es una clase,
previamente definimos la clase Ticket.
Las clases son objetos
Las clases son objetos especiales, le podemos mandar mensajes, aumentar
métodos, pasar como argumento, etc.
En el ejemplo de la clase Ticket, vamos a aumentarle un método que nos diga de una
lista de objetos ticket cual es el más caro. Utilizaremos la operación sort_by:
def Ticket.most_expensive(*tickets)
tickets.sort_by {|t| t.price }.last
end
Ya podemos saber de una lista cual es el mas caro:
th = Ticket.new(“Town Hall”, “11/12/13”) (esto ya lo creamos)
cc = Ticket.new(“Convention Center”, “12/13/14”) (esto ya lo creamos)
fg = Ticket.new("Auditorio Nacional", "13/14/15")
th.price = 12.55
cc.price =10.00
fg.price = 18.00
• irb(main):137:0> highest = Ticket.most_expensive(th, cc, fg)
• => #
puts “El ticket con el precio más alto es el del venue #{highest.venue}.”
Cuando usar un class method
En el ejemplo le mandamos el mensaje
most_expensive a la clase Ticket y no a un
objeto en particular ticket.
Esta operación puede verse desde arriba, algo
que hacemos con los tickets en general y no con
cada objeto ticket en individual.
Es importante entender que cuando definimos
Ticket.most_expensive es un método que puede
accederse a través de un objeto clase y no a
través de sus instancias.
Notación
Ticket#price El instance
Se puede hacer method price en
referencia a métodos la clase Ticket
Ruby de la siguientes
formas: Ticket.most Method class
_expensive most_expensive,
en la clase Ticket
Ticket::most Igual que el
_expensive anterior.
CONSTANTES
class Ticket
VENUES = [“Convention Center”,
“Auditorio Nacional”, “Town Hall”]
end
puts “The venues are”
puts Ticket::VENUES
La notación :: enmarca la constante VENUES
dentro de la clase conocida por la constante y
lista los valores de la misma.
HERENCIA
La relación entre un caso general y uno específico puede
expresarse con la técnica conocida como herencia. La
herencia es una relación entre dos clases, ejemplo:
class Publication
attr_accesor :publisher
end
class Magazine < Publication
attr_accesor :editor
end
Magazine es una subclase de Publication. Y Publication
es una superclase de Magazine.
Modelo de Cascada
En la herencia cada clase tiene sus propios métodos pero
las clases de más abajo en la cadena de la herencia
pueden tener los métodos definidos arriba. En el
ejemplo:
• Hasta arriba en la clase Publication se ponen todos los
métodos y accessors que se quiere que cada
publicación tenga.
• En cada subclase, se definen los métodos que cada tipo
particular de publicación queremos que tenga. Una
instancia de la subclase Magazine tiene acceso a todos
los métodos que definimos: aquellos en la superclase y
también los de la subclase.
ActiveRecord y herencia
class Xxxx < ActiveRecord::Base
Después veremos como las clases heredan
de una clase predefinida,
ActiveRecord::Base, para el manejo de
bases de datos.
Métodos en ActiveRecord
ActiveRecord crea automáticamente métodos que
corresponden a los campos de las tablas de la base de
datos.
Si tenemos una tabla ticket y tiene un campo venue,
cuando creamos un objeto ticket, ese objeto ya tiene un
método venue=, ya no se tiene que escribir.
Estos métodos además de identificar el valor, hacen la
integridad referencial en una variable instancia.
Existen formas de llenar el objeto con los valores que
queremos que tenga. Por ejemplo, cuando estamos
procesando una form Web, podemos depositar un juego
de valores en un objeto proporcionando el nombre del
campo que se usa en la form.