miércoles, 21 de noviembre de 2007

Tema 11: Send & Method_Missing

Send

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

¿Qué es xml?

-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 apt­get 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 h1
Generará lo siguiente:
Encabezado h1
Especificando 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
    Ejemplo de uso librería XMLBUILDER y ficheros

    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.


    $! es una variable global especial que contiene el mensaje de la excepción. Si no se pasa mensaje de excepción, $! contiene el nombre de la clase a la que está asocidada.

    Tema 7: Herencia

    La herencia es uno de los mecanismos de la programación orientada a objetos, por medio del cual una clase se deriva de otra de manera que extiende su funcionalidad.

    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

    En programacion, recorrer un array, es un proceso en el que hay que tener en cuenta varias cosas:
    -Un bucle para recorrer el array
    -Saber la longitud del array
    -Recuperar cada elemento para saber si es el que buscamos
    Ejemplo:

    a = [1, 2, 3]
    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 = [1, 2, 3]
    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:

    def Hola
    yield
    yield
    yield
    end

    "tenemos un metodo, que mediante el yield llama al bloque, invocando el contenido del bloque"

    Hola{puts "Hello"}

    "Bloque simple que muestra Hello"

    El resultado por pantalla sería:

    Hello
    Hello
    Hello

    Los bloques pueden recibir parámetros, y la última expresion evaluada en el bloque se entrega al método como el valor del yield.

    Ejemplo:

    class Array
    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:

    [1,2,3,4,5,6].impares{|e| e**2}

    o mediante los elementos do .. end:

    [1, 3, 5, 7, 9].find do |v|
    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:

    class File
    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

    Partimos de que casi todo en ruby es una expresion, es decir todo devuelve un valor. Lo que en otros lenguajes son declaraciones, en ruby son expresiones,por ejemplo:
    a = if true

    Caracteristicas:
    - Posibilidad de encadenar expresiones.
    - Contiene un paquete basico de operacion (+, ­, *, /, etc), estas operaciones son en realidad llamadas a metodos.
    a.+(b)
    - Como sabemos todo en ruby son objetos, luego se pueden redefinir operaciones, es decir, metodos
    - Podemos encadenar igualdades, cosa que en otros lenguajes no es posible, por ejemplo:
    a = (b = 1 + 2) + 3
    - Las igualdades se pueden hacer en lugares donde seria imposible en otros lenguajes, como por ejemplo dentro de un if, un while o en una llamada a un metodo

    Asignacion paralela:
    - La simplicidad de ruby hace posible el intercambio de valores de variables, sin necesidad del uso de auxiliares:
    a,b = b,a
    - Cuando una asignación tiene mas de un valor izquierdo, la expresion de asignacion retorna un array de los valores derechos.
    - 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:
    a = [1, 2, 3, 4]
    b, *c = a » b == 1, c == [2, 3, 4]

    Expresiones boleanas:
    - Todo lo que no sea false o nil, es true