miércoles, 21 de noviembre de 2007
Tema 11: Send & Method_Missing
Característica avanzada de Ruby que
permite invocar un método a partir de su
nombre.
class Persona
def saludar
puts "Hola soy una persona"
end
end
p = Persona.new
p.saludar
p.send(:saludar)
p.send("saludar")
Permite escribir código que invoque a
métodos que no existen todavía.
El identificador del método puede
obtenerse de diversos sitios, entrada de
teclado, base de datos, fichero...
method_missing
Cuando una clase en Ruby no implementa
un método se llama al método
method_missing.
Por defecto lanza una excepción(NoMethodError), pero se
puede sobreescribir este comportamiento(ver ejemplo).
Recibe dos parámetros, el identificador del
método invocado y la lista de argumentos.
Ejemplo:method_missing
class Persona
def saludar
puts "Hola soy una persona"
end
def method_missing(id, *args)
puts "Yo no puedo #{id}"
end
end
method_missing
p = Persona.new
p.saludar # Hola soy una persona
p.caminar # Yo no puedo caminar
Tema 10: XMLBUILDER
-Su nombre viene de eXtenseble Markup Language (lenguaje de
marcas extensible)
Un lenguaje de marcado o lenguaje de marcas es una forma de
codificar un documento que, junto con el texto, incorpora etiquetas o marcas que contienen información adicional acerca de la estructura del texto o su presentación. El lenguaje de marcas más extendido es el
HTML
XML fue desarrollado por un Grupo de Trabajo SGML (originalmente
conocido como "SGML Editorial Review Board") formado bajo los
auspicios del Consorcio World Wide Web (W3C), en 1996.
Los objetivos de diseño de XML son:
• Debe ser directamente utilizable sobre Internet.
• Soportar una amplia variedad de aplicaciones.
• Debe ser fácil la escritura de programas que procesen
documentos XML.
• Los documentos XML deben ser legibles por humanos y
razonablemente claros.
• El diseño debe ser preparado rápidamente, además, de ser
formal y conciso.
• Los documentos XML deben ser fácilmente creables.
Instalando rubygems y builder
Se nos ofrece una librería que nos ayuda a construir esto de forma
sencilla. La librería en cuestión es 'builder', y tenemos que instalarla, ya que no viene con el paquete básico de ruby.
Para instalarla, debemos utilizar rubygems, que es un gestor de librerías que nos sirve para instalar, eliminar y actualizar las librerías que tengamos instaladas en el equipo.
Para saber si tenemos instalado rubygems, abrir un terminal y escribir
gem –version
Si da un error, debemos intalar rubygems en nuestro equipo.
La instalación desde linux es bastante fácil.
En un terminal escribir lo siguiente:
sudo aptget install rubygems
Saldrán unas cuantas cosas en la consola y al final un mensaje que indica que se ha instalado correctamente.
A continuación se debe escribir lo siguiente para instalar el paquete builder:
gem install builder
Igual que antes, saldrán unas cuantas cosas en la pantalla. Salvo que se lea un mensaje de error, quedará bien instalado en nuestro ordenador.
En el caso de que falle algún paquete escribir la siguiente linea:
export RUBYOPT=rubygems
Crear un documento xml con builder:
Lo primero de todo es crear una variable que represente al documento xml que vamos a escribir.Para ello utilizamos el método Builder::XmlMarkup.new Este método recibe como parámetro el destino, (identificado por la clave :target ) donde se escribirá lo que vayamos haciendo con el objeto que acabamos de crear (debe responder al método <<) Se pueden especificar más parámetros, como el número de espacios que se incluirán al anidar elementos o el margen inicial en el que se empezará a escribir.
Ejemplo x= Builder::XmlMarkup.new:target => $stdout
Con esto, todo lo que se escriba en la variable x se escribirá por la salida estándar.
Escribiendo etiquetas:
Con todo lo anterior, ya tenemos el documento preparado para empezar a escribir la información que queramos en ella.
Para crear una etiqueta, simplemente llamamos al método:
x.h1 "Encabezado h1Generará lo siguiente:
Encabezado h1Especificando atributos en una etiqueta
Para especificar algun tipo de atributo, se hace mediante un hash, en el que la clave será el nombre del atributo y el valor de dicha clave, el valor que tomará el atributo.
x.h1 "Encabezado h1", :id => 'encabezado' escribirá
Encabezado h1
Anidando etiquetas
Podemos anidar etiquetas a base de abrir bloques:
x.ul {
x.li 'Manzana', :class => 'fruta'
x.li 'Fresa', :class => 'fruta'
x.li 'Albaricoque', :class => 'otra_clase'
}
Daría como resultado
- Manzana
- Fresa
- Albaricoque
Otra forma de hacerlo seria:
x.tag!(:ul, :id => 'lista_frutas'){
x.li 'Manzana', :class => 'fruta'
x.li 'Fresa', :class => 'fruta'
x.li 'Albaricoque', :class => 'otra_clase'
}
Daría como resultado
- Manzana
- Fresa
- Albaricoque
require "persona"
require "builder"#incluida en libraria
p1=Persona.new("Pepito","Gonzalez","29")
p2=Persona.new("Raquel","Blanco","31")
p3=Persona.new("Rodrigo","Fernandez","32")
personas=Array.new
personas<< < f, :indent => 2)
x.personas{
personas.each do |elemento|
x.tag!(:persona, :edad => elemento.edad){
x.nombre elemento.nombre
x.apellido elemento.apellidos
}
end
}
end
Este código generaría la siguiente salida en un fichero:
Pepito
Gonzalez
Raquel
Blanco
Rodrigo
Fernandez
Tema 9: Ficheros
Introducción
Definición de fichero (o archivo): Es un conjunto de información que se almacena en algún medio de escritura que permita ser leído o accedido por un equipo informático.
Un fichero es identificado por un nombre y la descripción de la carpeta o directorio que lo contiene. Los ficheros informáticos se llaman así porque son los equivalentes digitales de los ficheros en tarjetas, papel o microfichas del entorno de oficina tradicional. Los ficheros informáticos facilitan una manera de organizar los recursos usados para almacenar permanentemente información dentro de un equipo informático.
Ficheros en Ruby
Ruby define una sola clase base, IO, para gestionar toda la entrada y salida. De esta clase base heredan File y BasicSocket, para dar un comportamiento más especializado, pero los principios se mantienen iguales para todos.
La clase File
Permite trabajar con los ficheros.
Como era de esperar, se puede crear un nuevo objeto de fichero con
File.new
unFichero=File.new("ficheroprueba","r")
#...procesar el fichero
unFichero.close
Parámetros:
File.new(nombre_del_fichero,modo_de_acceso)
Debemos especificar qué es lo que queremos hacer con el fichero. Por defecto abren en modo lectura.
Los modos de acceso al fichero son los siguientes:
r Sólo lectura, poniendo el puntero de lectura al principio (por defecto).
r+ Lectura/escritura,empezando por el principio del fichero.
w Sólo escritura. Borra el contenido del fichero si existe o crea uno nuevo en caso contrario
w+ Lectura/escritura. Borra el contenido del fichero si existe o crea uno nuevo en caso contrario
a Sólo escritura. Sitúa el puntero al final del fichero si existe. Si no, lo crea.
a+ Lectura/escritura, poniendo el puntero al final del fichero si existe. Crea uno nuevo en el caso de que no exista
b (Sólo en DOS/Windows) Modo binario. Puede aparecer con cualquiera de los anteriores.
Otra forma de especificar los modos de acceso:
La clase file tiene declaradas las siguientes constantes para poder abrir el fichero de forma que se ajuste más a nuestras necesidades:
APPEND Abre el fichero en modo 'añadir'. Lo que se escriba, será al final del fichero.
CREAT Crea el fichero al abrirlo si no existe.
EXCL Al usarlo con CREAT, se lanzará una excepción si existe el fichero.
NONBLOCK Abre el fichero, pero no lo bloquea.
RDONLY Abre el fichero en modo sólo lectura
RDWR Abre el fichero en modo lectura/escritura
TRUNC Abre el fichero y borra su contenido si existe
WRONLY Abre el fichero en modo sólo lectura
Estos modos se pueden combinar mediante el operador '|' que hace un or a nivel de bit
ejemplo: file.new(“nombre”, File::APPEND|File::WRONLY)
Métodos varios
Los mismos métodos que has estado usando para la E/S “simple'' están disponibles para todos los objetos de tipo fichero. Así, gets lee una línea de la entrada de la terminal, y unFich.gets lee una línea del objeto fichero unFich.
Sin embargo, los objetos de E/S tienen una serie de métodos de acceso adicionales, pensados para hacer nuestra vida más fácil:
Por ejemplo el método File.open también abre un fichero. En su uso normal, hace lo mismo que File.new . Sin embargo, si hay un bloque asociado a la llamada, open se comporta de manera diferente: en vez de devolver un nuevo objeto File, invoca al bloque, pasándole el fichero acabado de abrir como parámetro. Cuando el bloque termina, el fichero se cierra automáticamente.
Como responsables programadores, cerramos el fichero para asegurarnos de que todos los datos que hay en memoria se escriben y que todos los recursos relacionados se liberan.
Abrir/crear ficheros:
new
open
Tratamiento de cadenas:
readline: lee una línea del fichero. Lanza una excepción si se llega al final.
gets: lee una línea del fichero. Si se llega al final de fichero devuelve nil.
puts: Escribe una línea en el fichero. Termina con un salto de línea.
write: Escribe una línea, sin introducir el salto de línea.
print: Igual que write.
Iteradores:
each_line( separador ){ bloque }: Ejecuta el bloque para cada una de las líneas. El separador se usa para identificar cada línea. Por defecto \n
IO.foreach( ruta_fichero ){ bloque }: Abre el fichero en modo lectura y ejecuta el bloque para cada línea.
IO.readlines( ruta_fichero ): Devuelve el fichero en un array
#La clase Alumno implementa las caracteristicas de un alumno, junto con la posibilidad de almacenar dicho alumno en un fichero.
class Alumno
def initialize n, a, dni
@nom = n
@ape = a
@dni = dni
end
def almacena
#El fichero se abre en modo lectura y escritura,
#poniendo el puntero al final del fichero
f = File.new("Alumnos.txt", "a+")
cadena = "#{@nom}, #{@ape}, #{@dni.to_s}"
f.puts(cadena)
f.close
end
end
#MAIN
#Creamos tres alumnos y los almacenamos en el fichero
a = Alumno.new("Ivan", "Alvarez", 53534512)
b = Alumno.new("Laura", "Nuevo", 53534512)
c = Alumno.new("Diego", "Perez", 53534512)
a.almacena
b.almacena
c.almacena
#Cargamos alumnos del fichero, y los mostramos por pantalla
puts "\nCargamos los alumnos del fichero: "
IO.foreach( "Alumnos.txt" ) do |a|
array = a.split(", ")
alumno = Alumno.new(array[0], array[1], array[2])
print "#{alumno.nom}, #{alumno.ape}, #{alumno.dni}"
end
Tema 8: Excepciones
En un programa en ejecución pueden suceder acciones inesperadas. Las excepciones tienen como función solucionar los problemas que dicahs acciones pueden ocasionar.
En Ruby podemos decir que una excepción es un objeto, que se crea cuando se da una situación
anómala durante la ejecución de nuestro código.
Sentencia rescue:
begin
# código susceptible de generar una excepción
rescue [tipo de excepción]
# código que trata el error producido
else
# Se ejecuta si no se produce la excepción
end
El bloque de código marcado con begin se ejecutará hasta que haya una excepción, lo que provoca que el control se transfiera a un bloque con el código de gestión de errores, aquel marcado con rescue.
Sentencia ensure:
begin
#código
rescue
#mas código
ensure
#codigo que se ejecutará siempre
end
El bloque de código de ensure se ejecuta independientemente de si se produce o no la excepción. tiene como finalidad realizar ciertas acciones cuando el método termina su ejecución.
Ensure debe colocarse al final de los rescues.
Sentencia retry:
begin
...
rescue
retry
end
Se puede utilizar la sentencia de control retry para repetir la iteración del código del bloque begin.
Sentencia raise:
begin
raise(ArgumentError, "error en el argumento")
rescue
puts $!
end
La sentencia raise es la encargada de lanzar las excepciones. La cadena que describe la excepción se le pasa como argumento. El argumento es opcional y en caso de no llevarlo crea una excepción RuntimeError o relanzaría la excepción capturada si nos encontraramos dentro de un rescue.
Tema 7: Herencia
La herencia en Ruby se simboliza mediante el operador < .
#La clase "Luchador" contiene los datos que debe tener todo luchador, por ejemplo vida, fuerza,... De igual forma define acciones comunes a todos los luchadores, es decir, los metodos golpear, recibir_golpe,...
class Luchador
def initialize v, f, d, p, n
@vida = v
@fuerza_ataque = f
@defensa = d
@prob_ataque = p
@nombre = n
end
def golpear
(...)
end
def recibir_golpe x
(...)
end
def vivo?
(...)
end
end
#Todo boxeador es un luchador, por lo tanto tiene todas las características de un luchador, y a parte, características específicas de un boxeador. La herencia se denota con el operador "<", de modo que la clase "Boxeador" hereda de "Luchador": class Boxeador <>
En este caso, un boxeador se comporta de un modo determinado al recibir un golpe, por ese motivo se redefine el método "recibir_golpe".
class Boxeador < Luchador
def initialize n
#super llama al constructor de la clase Luchador
super 90, 15, 2, 0.3, n
end
def recibir_golpe x
(...)
end
end
#Todo karateca es un luchador, igual que en el caso anterior, tiene todas las #características de un luchador, y a parte, características específicas de un karateka.
En el caso del karateka, el modo de golpear es diferente, por eso se redefine el método "golpear".
class Karateka < Luchador
def initialize n
super 100, 10, 4, 0.5, n
end
def golpear
(...)
end
end
Tema 6: Bloques e iteradores
-Un bucle para recorrer el array
-Saber la longitud del array
-Recuperar cada elemento para saber si es el que buscamos
Ejemplo:
for i in 0..a.length-1
a[i] += 1
end
En ruby existe una manera más facil de hacer esto, utilizando los iteradores.
Un iterador es un método capaz de invocar a un bloque de código de forma repetida.
El metodo "each" es un ejemplo de iterador:
a.each{|elemento| elemento += 1}
Otros ejemplos de iteradores: find, collect,select...
Esto nos libera de código y lo hace más sencillo, ya que el propio iterador implementa el blucle, y se le puede pasar cualquier operación que queramos hacer con el array.
¿Que son los bloques?
En Ruby es un modo de agrupar sentencias, dando una mayor flexibilidad pero con algunas particularidades:
- Un bloque puede aparecer solamente en el código adyacente a la
invocación de un método
-No se ejecuta cuando se encuentra
-Dentro del método se le hace una llamada "yield" y se ejecuta.
Vamos a verlo con un ejemplo sencillo:
yield
yield
yield
end
"tenemos un metodo, que mediante el yield llama al bloque, invocando el contenido del bloque"
"Bloque simple que muestra Hello"
El resultado por pantalla sería:
Hello
Hello
Ejemplo:
def find
for i in 0...size
value = self[i]
return value if yield(value)
end
return nil
end
end
[1, 3, 5, 7, 9].find {|v| v*v > 30 } >> 7
Los bloques pueden definirse mediante llaves:
o mediante los elementos do .. end:
v*v > 30
end
Por último los bloques pueden usarse para definir una porción de código que
debe ejecutarse bajo algún tipo de control transaccional, por ejemplo
operaciones con ficheros.
Ejemplo:
def File.openAndProcess(*args)
f = File.open(*args)
yield f
f.close()
end
end
File.openAndProcess("testfile","r") do |aFile|
print while aFile.gets
end
Tema 5: Expresiones
Caracteristicas:
- Posibilidad de encadenar expresiones.
- Contiene un paquete basico de operacion (+, , *, /, etc), estas operaciones son en realidad llamadas a metodos.
- Podemos encadenar igualdades, cosa que en otros lenguajes no es posible, por ejemplo:
Asignacion paralela:
- La simplicidad de ruby hace posible el intercambio de valores de variables, sin necesidad del uso de auxiliares:
- Si una asignación contiene mas valores izquierdos que derechos, los valores izquierdos excendentes contendran nil.
- Si una asignación mútiple contiene más valores derechos que izquierdos, los valores derechos sobrantes seran ignorados.
- Si el último valor izquierdo esta precedido por un asterisco, todos los valores derechos sobrantes seran asignados como un array, por ejemplo:
b, *c = a » b == 1, c == [2, 3, 4]
Expresiones boleanas:
- Todo lo que no sea false o nil, es true