Está en la página 1de 10

William Viana y Andreu Belmonte 30

23
24 def to_s
25 Dias_semana [ @numdia ]
26 end
27 end
28
29 i f $0 == __FILE__
30 l a b o r a l = DiaSemana . new ( " l u n e s " ) . . DiaSemana . new ( " v i e r n e s " )
31 hoy = DiaSemana . new ( " domingo " )
32
33 i f l a b o r a l === hoy
34 p u t s "#{hoy } e s un d i a l a b o r a l "
35 else
36 p u t s "#{hoy } no e s un d i a l a b o r a l "
37 end
38
39 l a b o r a l . each { | d i a | p r i n t "#{d i a } " }
40 end

$ ruby diasemana . rb
domingo no e s un d i a l a b o r a l
l u n e s martes m i e r c o l e s j u e v e s v i e r n e s
$

El constructor lo primero que hace es comprobar si se le ha pasado un día de la semana válido: lo comprueba
mirando si está en el array Dias_semana con el método include?. Si está almacena la posición que ocupa el
día en el array (equivale a guardar el día en formato numérico empezando con lunes = 0). Si no está lanza
una excepción de tipo ArgumentError con el método raise. El método <=> (también conocido como nave
espacial) compara dos objetos y devuelve -1 si el primero es menor que el segundo, 0 si son iguales o 1 si el
segundo es menor que el primero. Eres bastante mayorcito para saber que hace el método succ El método to_s
sirve para poder imprimir nuestro objeto por pantalla. La línea 29 es un truco para saber si el programa ha sido
ejecutado directamente (útil si lo queremos probar). Cómo puedes ver en la línea 30 una instancia de nuestra
clase se crea con el nombre de la clase seguido de la palabra new y los argumentos que recibe el constructor
entre paréntesis.
Las clases pueden tener métodos de la clase. Un método de una clase no está asociado a un objeto de esa clase,
sino a la propia clase. Para llamarlo se hace con el nombre de la clase seguido de :: o . y el nombre del método.
William Viana y Andreu Belmonte 31

La clase File por ejemplo tiene algunos métodos de clase:


1 File : : exists ? #comprueba s i un f i c h e r o e x i s t e
2 F i l e : : chmod #cambia l o s p e r m i s o s de un f i c h e r o s
3 F i l e : : rename #renombra un f i c h e r o

Definir métodos de una clase se hace de la misma forma: con el nombre de la clase seguido de :: o . y el nombre
del método.

5.1.1 Acceso

Al igual que otros lenguajes orientados a objeto como Java o C++ también se puede definir en Ruby el control
de acceso a una clase. Los modos de acceso son los usuales:
1 c l a s s Foo
2
3 def i n i t i a l i z e #por d e f e c t o e s p r i v a d o
4 ...
5 end
6
7 private #s o l o a c c e s i b l e d e s d e d e n t r o d e l o b j e t o
8 def bar
9 ...
10 end
11 p u b l i c #a c c e s i b l e d e s d e f u e r a d e l o b j e t o
12 def f o o
13 ...
14 end
15 p r o t e c t e d #p r i v a d o para e l e x t e r i o r p e r o a c c e s i b l e a l a s c l a s e s que heredan
16 def f o o b a r
17 ...
18 end
19
20 #Tambien s e puede d e f i n i r e l c o n t r o l de a c c e s o d e s p u e s de d e f i n i r l o s metodos
21 p r i v a t e : bar
22 p u b l i c : foo
23 p r o t e c t e d : f o o b a r
24
William Viana y Andreu Belmonte 32

25 end

5.1.2 Herencia

Como curiosidad, todos las clases que definas Heredar es sencillo.


por defecto heredan de una clase padre lla-
1 class Peli
mada Object con algunos métodos útiles que
2 def i n i t i a l i z e ( t i t u l o , d i r e c t o r , d u r a c i o n , r e p a r t o )
puedes sobreescribir y a veces es recomendable 3 @titulo = t i t u l o
que lo hagas. Cuando instancias tu nueva clase 4 @director = director
con el método new, estás llamando al método 5 @duracion = d u r a c i o n
new de la clase Object quien luego le pasa al 6 @reparto = r e p a r t o
método initialize de tu clase todos los argu- 7 end
mentos que le han pasado a él. 8
9 def to_s
10 " T i t u l o : #{@ t i t u l o }\n "+\
11 " D i r e c t o r : #{@ d i r e c t o r }\n "+\
12 " Reparto : #{@reparto }\n "+\
13 " Duracion : #{@duracion }\n "
14 end
15 end
16
17 c l a s s Dvd < P e l i
18 def i n i t i a l i z e ( t i t u l o , d i r e c t o r , d u r a c i o n , r e p a r t o , p r e c i o , n _ d i s c o s )
19 super ( t i t u l o , d i r e c t o r , d u r a c i o n , r e p a r t o )
20 @precio = p r e c i o
21 @numero_discos = n _ d i s c o s
22 end
23
24 def to_s
25 super + " P r e c i o : #{@ p r e c i o }\n "+\
26 " Numero de d i s c o s : #{@numero_discos }\n "
27 end
28 end

La clase Dvd es una clase hija de la clase Peli. Los métodos de la clase Dvd, al llamarse igual, sobreescriben los
métodos heredados pero con el método super dentro de un método se llama al método del mismo nombre de la
William Viana y Andreu Belmonte 33

clase padre.
Ruby no soporta herencia múltiple pero lo solventa con algo llamado Mixins, que veremos dentro de nada.

5.2 Módulos
Un módulo es algo parecido a una clase pero más sencillo. Se utiliza para agrupar cosas que tienen relación pero
que no forman una clase de manera natural. Dentro de un módulo puedes tener métodos, variables o clases. Para
acceder a algo de un método se utiliza el operador ::. De hecho has estado utilizando un módulo todo ese rato sin
darte cuenta. Los métodos print, puts y gets pertenecen al módulo Kernel y deberías estar llamándolos como
Kernel::print, Kernel::puts o Kernel::gets, pero como son métodos muy utilizados el intérprete de Ruby los
busca automáticamente en el módulo Kernel y por eso puedes omitirlo y simplemente poner puts.

5.3 Mixins
Un mixin, del inglés mezcla, no es más que una clase con un módulo dentro. Tienes una clase, le metes un módulo,
ya tienes un mixin. Dentro de una clase puedes meter cuantos módulos te apetezca y ésta “heredará” todo lo que
tenía el módulo. Los módulos dentro de una clase se comportan como si de una clase padre se trataran. Antes
hemos creado un mixin con el ejemplo de la clase DiaSemana. Incluimos el módulo Comparable y ganamos un
montón de métodos gratis, sólo había que cumplir una condición, tener definidos los métodos <=> y succ, ya
que Comparable asume que la clase que lo hereda los tiene definidos.
6 Si no lo apunto se me olvida

6.1 La clase File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35


6.2 Bienvenido al mundo falible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.3 ¿Qué voy a ver en el cine? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

34
William Viana y Andreu Belmonte 35

Bueno, trabajar con ficheros en Ruby es muy sencillo, no quería incluir un capítulo entero para ello pero tenía que
contarlo en algún lado. Y cómo me quedará muy cortito también incluyo un poco de tratamiento de excepciones
y un último ejercicio cañero.

6.1 La clase File


Veamos todo sobre la práctica
1 #Leer
2 f i c h = F i l e . new ( " f i c h e r o " , " r " ) #e l segundo argumento e s e l modo de a p e r t u r a .
3 f i c h . e a c h _ l i n e { | l i n e a | p u t s l i n e a } #r e c o r r e e l f i c h e r o l i n e a a l i n e a
4
5 #o p c i o n a l m e n t e p u e d e s u s a r
6 fich . readline #que l e e una l i n e a y s e s i t u a para l e e r l a s i g u i e n t e
7 l i s t a = f i c h . r e a d l i n e s #d e v u e l v e un a r r a y de l i n e a s
8 cadena = f i c h . r e a d #d e v u e l v e una cadena con t o d o e l t e x t o d e l f i c h e r o
9
10 #E s c r i b i r
11 f i c h = F i l e . new ( " f i c h e r o " , "w" ) #a b r e e l f i c h e r o para e s c r i b i r
12 f i c h << " Hola mundo\n "
13 f i c h . c l o s e #c i e r r a e l f i c h e r o
14
15 #tambien p u e d e s u s a r :
16 f i c h . p u t s " Hola mundo "
17 f i c h . p r i n t " Ruby mola "
18
19 #Otra forma de h a c e r l o
20 F i l e : : open ( " f i c h e r o " ) . e a c h _ l i n e do | l i n e a |
21 #p r o c e s a d o
22 end
23 #Abre e l f i c h e r o , l o p r o c e s a en e l b l o q u e y a l s a l i r l o c i e r r a

6.2 Bienvenido al mundo falible


Cómo todo lenguaje moderno Ruby tiene un tratamiento de excepciones moderno. Para hacerlo encierras el código
susceptible de lanzar una excepción a partir de la palabra begin, capturamos la excepción con la palabra rescue
William Viana y Andreu Belmonte 36

seguida del tipo de excepción. Si el bloque de código es susceptible de lanzar diferentes tipos de excepciones se
puede incluir un rescue para cada una. En el rescue es dónde tratas la excepción. Puede hacer que se vuelve
a ejecutar el código del begin con un retry o simplemente lanzar tu una excepción con raise.
1 begin
2 f i c h = F i l e . new ( " f i c h e r o " )
3 f i c h . each_line { | l i n e a | puts l i n e a }
4 fich . readline
5 rescue EOFError
6 r a i s e EOFError , " s e ha a l c a n z a d o e l f i n a l d e l f i c h e r o "
7 end

ri es un programa que muestra documentación 6.3 ¿Qué voy a ver en el cine?


sobre métodos, clases y módulos de Ruby. Es Soy una persona un poco maniática y normalmente antes de ir al cine compruebo la nota que tiene la película
bastante fácil de usar. en el imdb. Ahora, estaría bien tener una aplicación que me bajara la cartelera del cine al que voy y que me
ri palabra_clave ordenara las pelis según sus notas, así puedo decidir que peli quiero ver. Te propongo como ejercicio que lo
hagas, ya hemos visto antes como bajar la cartelera de los Neocine, mitad de la faena hecha, te recomiendo que
lo metas en un módulo y lo guardes en un fichero que se llame por ejemplo neocine_parser.rb. Ahora con cada
título de una peli tendrás que bajar información sobre la película, cómo no hay imdb en castellano, usaremos
film-affinity que también está muy bien. Básicamente sólo tienes que parsear la web. Para buscar información
en film-affinity usa esta uri: http://www.filmaffinity.com/es/search.php?stext=titulo_peli&stype=’title’. Dónde
pone titulo_peli sustituyes por el título de la peli que quieres buscar y ten en cuenta que por ejemplo los espacios
en blanco los tendrás que sustituir por “%20” y los carácteres con acentos por sus respectivos códigos. Vas a tener
que buscar algo de información, es un buen momento para aprender a usar ri para buscar en la documentación
de Ruby. Suerte :P Bueno, vale, no te voy a dejar tan tirado, colgaré cuando me apetezca una solución y la
pondré aquí http://www.aditel.org/~wviana/ruby/Cartelera.tar.gz
7 Qt4-Ruby

7.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
7.2 Estructura de un interfaz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
7.2.1 Signal’n’Slots: Connecting Peoples’ objects . . . . . . . . . . . . . . . . . . . . . . . . . 39
7.3 Diseño del interfaz: Designer-qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
7.4 Implementación de la funcionalidad del interfaz . . . . . . . . . . . . . . . . . . . . 44
7.5 Aplicación principal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

37
William Viana y Andreu Belmonte 38

7.1 Introducción
Qt es una biblioteca multiplataforma para desarrollar interfaces gráficas de usuario. Fue creada por la compañía
noruega Trolltech. Qt es utilizada en KDE, un entorno de escritorio para sistemas como linux o FreeBSD, entre
otros. Utiliza el lenguaje de programación C++ de forma nativa.
Qt4-ruby son los binding de Qt4 para ruby. Permite realizar aplicaciones gráficas utilizando dichas librerías pero
utilizando nuestro lenguaje de programación favorito ruby ;).
El proceso se dividirá básicamente en dos etapas. En la primera de ellas diseñaremos como será nuestra aplicación
visualmente: como le mostraremos por pantalla al usuario los datos y como podrá introducirlos él. En una segunda
fase definiremos como interactuar con cada uno de los elementos y como interactuarán los elementos entre sí.
«Programming isn’t about what you know; it’s El objetivo final de este documento no es enseñar como trabajar con las Qt, sino proporcionar los conocimientos
about what you can figure out. As long as you y las herramientas necesarias para poder utilizarlas con ruby y describir un breve ejemplo de como hacerlo.
know where to find out the things you forgot,
you’re doing just fine.» Chris Pine 7.2 Estructura de un interfaz
Qt está estructurado en clases. Hay clases que están en lo alto de la jerarquía y hay otras que heredan de estas.
No vamos a entrar a explicar demasiado detalladamente como se estructura, pero a grandes rasgos (y teniendo
en cuenta los cambios que ha habido con la nueva versión) las clases que más comúnmente usaremos las podemos
dividir en estos grandes grupos:
QWidget:: Clase base para crear varios tipos de ventana
• QMainWindow:: Ventana principal de aplicación, posiblemente con menús, barras de herramientas, barras
de estado,. . .
• QDialog:: Ventana de dialogo para tareas simples y a corto término: diálogos de error, abrir archivos,
seleccionar color,. . .
QLayout:: clase base para el manejo de geometrías, redimensionamiento automático para componer diálogos más
complejos:
• QBoxLayout:: de ésta clase heredan QHBoxLayout y QVBoxLayout para construir diseños en horizontal o
vertical.
• QGridLayout:: útil para construir diseños en forma de cuadrícula
• QStackedLayout:: para crear un conjunto de widgets de los que solo se muestra uno cada vez
William Viana y Andreu Belmonte 39

De QWidget también heredan las clases de de los elementos básicos de un interfaz como pueden ser:
• QComboBox:: Lista emergente de datos, que puede ser editable para introducir nuevos elementos
• QLabel:: para mostrar texto e imágenes
• QPushButton botón
• QTextBrowser:: Caja de edición de texto con tags HTML

7.2.1 Signal’n’Slots: Connecting Peoples’ objects

Es posiblemente la mayor diferencia entre Qt y los otros toolkits de programación gráfica. Mientras la mayoría
Callback: es un puntero a una de otros entornos utilizan los callbacks en Qt usaremos los Signals y los Slotss.
función, que le pasas a una fun-
• Una Signal es emitida cuando un determinado evento ocurre, los objetos de Qt disponen de numerosos
ción de tratamiento de un deter-
eventos que generarán su correspondiente señal.
minado evento. Cuando ocurre un
evento en un objeto, la función de • Un Slot es una función que se llama como respuesta a una determinada señal (pero que también puede ser
tratamiento llama a nuestra fun- llamada directamente desde nuestro código).
ción callback.
Lo que tenemos que hacer es conectar cada señal que queremos tratar con un slot o incluso varios si fuera
También podemos conectar señales con necesario. .
señales: cuando se emite una señal, automáti-
Las Señales y los Slots no saben si están conectadas o si hay alguien conectado a ellas lo que garantiza que
camente ésta hace que se emita la segunda
estemos creando componentes independientes entre sí.
Tomemos como ejemplo un botón instanciado de la clase Qt::PushButton. Las acciones que podemos realizar con
un botón son:
Evento Señal emitida
Presionar el botón pressed
Dejar de presionarlo released
Pulsarlo: Presionar+Dejar clicked
Si queremos que nuestra aplicación trate el botón cuando sea pulsado, deberemos conectar su señal con un slot
que nosotros definamos:
\ t e x t i t {Qt } : : Obj ect . c o n n e c t ( @Boton , SIGNAL( ’ c l i c k e d ( b o o l ) ’ ) , s e l f , SLOT( ’ f u n c i o n ( ) ’ ) )