Sunday, November 1, 2009

Sobre editores, programación visual y demás yerbas

Perdón por la tardanza, pero acá seguimos con Ruby. :-)

La idea del tercer Post era estudiar los métodos en Ruby. Ese post quedara para la próxima semana, porque para esta me quede pensando en una duda que planteo Maximiliano en los comentarios del anterior post.


No voy a ser exhaustivo, sino tan solo explicar porque no confundir programación dentro del paradigma de objetos con la programación de Interfaces de usuario. Luego, me explayare en interesantes editores e IDEs para programar, en Linux y Windows, teniendo en cuenta los mas usados en Ruby.


Sobre la programación en objetos y la programación de GUI


El paradigma de objetos implica una visión abstracta y lógica de diversas entidades que existen en el mundo real. El paradigma de objetos obliga a ciertas reglas de construcción de objetos, manejo de memoria y técnicas o mecanismos particulares tales como envío de mensajes, herencia, polimorfismo, etc...


Todo lenguaje que soporta o implemente lo anterior, mas otras cuestiones adicionales, se considera un lenguaje que soporta el paradigma de objetos.


Con los objetos se realiza el modelo de datos y de comportamiento de una aplicación.


Por otro lado, las GUI (Interfaz Gráficas de Usuario) son una manera de representar un sistema ante los usuarios.


Pensemos en un sistema de 3 capas:


+-------------------------------------+
|---------Interfaz de usuario---------|
+-------------------------------------+
|----------Modelo de objetos----------|
+-------------------------------------+
|--------Modelo de datos físico-------|
|-----------(Base de datos)-----------|
+-------------------------------------+


El diagrama anterior nos muestra que el modelo de objetos esta entre la interfaz del usuario, y la base de datos física. Es decir, el modelo de objetos es el sistema, en memoria y trabajando. La interfaz de usuario es la forma amigable en que el usuario ingresa datos y pide que se ejecuten determinadas acciones. El modelo de datos físico es el almacenamiento permanente con alguna tecnología (Sistemas de archivos, SGBD, etc...)


De todo lo anterior podemos extraer varias conclusiones:


  • Los modelos de capas son muy ventajosos para los desarrolladores de aplicaciones, porque permite dividir el trabajo de una manera clara y natural.


  • Estudiar objetos no es estudiar las maneras que al usuario le gusta ver el sistema, sino estudiar la lógica interna de un lenguaje de objetos, como Ruby, Smalltalk, Python, etc...


  • La interfaz de usuario no solo es la GUI de ventana. Muchos grandes sistemas siguen funcionando en consolas de textos (sistemas financieros que es muy difícil o imposible dejarlos inoperativos aunque sea por un corto tiempo). La tendencia hoy en día es realizar aplicaciones Web, entonces allí la interfaz tampoco es "la ventana".
Con todo lo anterior, vemos que si estudiamos bien los objetos, la interfaz puede cambiar entre una y otra (y si esta bien hecho, debe poder cambiarse sin problemas) y puedo tener un mismo sistema en linea de comandos, en GUI y con interfaz web.


Ruby naturalmente permite realizar sistemas que interactúen con todas las interfaces. Naturalmente con las consolas de texto. Tiene Bindings para GTK, QT, WxWindows, etc... Y con Rails, su framework mas popular, se pueden desarrollar aplicaciones web.


Si se entiende bien el funcionamiento de un lenguaje, crear interfaces de usuario, sea web o sea GUI, es cuestión de agregar un modulo al lenguaje, aprender una API o mecanismo de interpretación adicional.


Editores de texto e IDEs para desarrollar con Ruby















Notepad++ (solo windows):
Es uno de los editores de software libre mas populares en plataformas Windows. Es de propósito general, con lo cual su integración con herramientas de Ruby es genérica (Resaltado de sintaxis y algún que otro plugin con funcionalidad menor).


Textmate (para rails y en OS X): Si se trabaja en plataformas MAC, Textmate es uno de los editores que mas se recomiendan para programar en Ruby, mas específicamente con Rails, por algunos elementos que hacen la tarea mucho mas sencilla. Es pago y de código cerrado.


Netbeans con plugins: Netbeans es el popular IDE desarrollado y mantenido por SUN, con una gran cantidad de plugins, entre ellos para Ruby y Rails, y también soporte para SVN nativo, ejecuciones de prueba del código, debbugin, etc... También es recomendado entre los desarrolladores de Ruby. Netbeans es multiplataforma.


Gedit con las mejoras de Textmate: Gedit es el bloc de notas del entorno de escritorio GNOME. En los últimos años este editor fue desarrollando mejoras orientadas a que se pueda usar como un editor para desarrollo. Al tener un sistema de plugins y agregados bastante interesante, desarrolladores se han orientado a mejorarlo para hacerlo mas potente. En particular, Jose ha hecho un trabajo excelente implementando plugins para que Gedit se acerque a Textmate en funcionalidad. La dirección del post principal en su blog es http://blog.nationcode.com/articles/2008/04/06/gedit-como-textmate-mejorado-para-rails-en-gnu-linux.


Komodo Editor: Editor OpenSource muy interesante. Es limitado porque hay otra versión paga y cerrada que es Komodo IDE. Se puede descargar desde su pagina http://www.openkomodo.com/


Geany: Editor ligero, bastante completo, y orientado a programadores. Otra buena alternativa a los editores usados comúnmente. Se puede descargar en http://www.geany.org/


VIM, Emacs: Clásicos editores de programación de entornos de desarrollo OpenSource. Son complicados para usuarios noveles, pero tienen muchos atajos y complementos que los hacen muy útiles para usuarios experimentados. La mayoría del desarrollo del Lenguaje Ruby fue hecho en Emacs.

En la próxima entrada, donde trataremos sobre métodos en Ruby, ya tendremos bastante mas código, así que pongan a punto esos editores ;-)

Fuentes consultadas:

http://rubytutorial.wikidot.com/introduccion

http://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos

Thursday, October 29, 2009

Notas de la clase 7 y guía de trabajos prácticos

El foco de esta clase fue introducción a análisis y diseño. Vimos un conjunto de estrategias que nos permite avanzar desde una especificación de un sistema (medianamente completa) a un diseño e implementación del mismo. Las estrategias que aplicamos con una combinación de lo propuesto por varios autores (Larman en lo referente a casos de uso y identificar comportamiento para cada uno, Wirfs-Brock en lo referente a la estrategia de sustantivos para identificar clases). Aquí les resumo cuales son los pasos a seguir cuando uno todavía no sabe por donde arrancar con el diseño.


  1. Listar los casos de uso. Que cosas puede hacer el usuario con el sistema? Por ahora nos alcanza con una frase que resuma cada caso de uso, por ejemplo, "calcular el peso de un contenedor".
  2. Subrayar todos los sustantivos en la especificación (enunciado). También hacer esto en mi lista de casos de uso dado que puedo haber introducido nueva información y vocabulario.
  3. Construir una lista con todos esos sustantivos. No descartar ninguno. En la lista incluyo los calificativos que acompañan, por ejemplo "Pieza de metal", "Ciudad destino", "Usuario vip". 
  4. Vamos a utilizar esa lista para construir un modelo del dominio (Larman le llama diagrama de conceptos). Es muy parecido a un diagrama de clases, pero todavia no puedo asegurar navegabilidad de las relaciones y todavia no hablo de comportamiento. Procedemos así: hasta que la lista este vacía (o ya no me sirva porque los sustantivos que quedan no me ayudan mucho) repito lo siguiente:
    1. De la lista tomo un sustantivo que creamos que, casi sin discusión, es una clase. Uso un poco de intuición, me pregunto cuales serían sus atributos si fuera una clase, me pregunto cuan central es ese concepto al problema, etc. Incluyo en el diagrama y lo tacho de la lista. Si en la lista hay un sinónimo para esa palabra, veo cual de las dos palabras representa mejor el concepto, uso esa y tacho las dos.
    2. Busco en la lista atributos obvios para esa nueva clase. Los incluyo en el diagrama y los tacho.
    3. Si en mi diagrama hay otras clases, pienso como se relacionan con la que acabo de agregar. Si hay relación de conocimiento la indico sin hablar todavía de navegabilidad (dirección de la flecha). También indico cardinalidad. Si creo que hay relación de especialización o generalización (herencia) también la indico. Recuerden preguntar "es_un"?".
    4. Busco en la lista para ver si alguna de las palabras en la lista describe los roles de las relaciones que agregué (etiquetas en los extremos de las relaciones).
    5. Contínuo, siempre eligiendo lo mas obvio, menos discutible, hasta que tengo un diagrama que a mi entender representa bien el dominio e incluye la mayoría de los sustantivos de la lista. Puede que me queden algunos sustantivos en la lista que no se donde ubicar.
  5.  Ahora, pienso en comportamiento. Tomo alguno de los casos de uso y pienso:
    1. Como estaría instanciado mi diagrama de clases para que ejecutar ese caso de uso tenga sentido (por ejemplo, debe existir una instancia de Container, con su colección de cajas inicializada y vacía). Que objetos deberían existir, como serían sus atributos, como estarían relacionados? Si puedo lo dibujo para no olvidarme (diagrama de instancias)
    2. Luego de que el caso de uso termine, como quedaría mi diagrama de instancias? Que nuevas instancias aparecen? Que atributos cambian? Que relaciones cambian? 
    3. Ahora pienso que tendrían que hacer mis objetos para llegar del estado inicial (1) al estado final (2). A quien le envío que mensaje con que argumentos? A quienes le envía mensajes ese? Agrego esos mensajes en la lista de los mensajes que debe entender cada una de las clases involucradas. En este punto pueden utilzar un diagrama de comunicación para documentar como es la cadena de envío de mensajes (ojo que hay cosas que no voy a intentar documentar el en diagrama para no complicarlo como iteraciones, ifs, etc). Si su diseño los va convenciendo, pueden ir implementando y probando en el workspace.
Práctica

Les dejo la práctica 7 en las que repito el enunciado visto en clase para que lo diseñen e implementen completamente (además de unos ejercicios de diseño e implementación simples) para

Notas de la clase 6 y guía de trabajos prácticos

Les debía las notas de la clase 6.

En esta clase hablamos principalmente sobre colecciones. De la jerarquia de colecciones de Squeak nos concentramos en OrderedCollection (tamaño dinámico, muy flexible), Set (elimina duplicados), Array (tamaño fijo, rápida) y SortedColection (ordenada), y Dictionary (cualquier objeto puede ser una clave).
Collections esta muy bien cubierto en el capítulo 9 de Squeak by Example.

Al hablar de Set, aprovechamos y vimos la diferencia entre igualdad (el mensaje #=) e identidad (el mensaje #==). Nunca redefinimos el #==. Es comun que redefinamos el #= en nuestras clases (por ejemplo para definir que dos personas son iguales si tienen el mismo DNI aunque haya alguna diferencia entre sus nombres, por ejemplo, por un error ortográfico). El set envia el mensaje #= para ver si un nuevo objeto ya esta incluido. Si quiero que compare por identidad utilizo un IdentitySet. Para leer mas sobre identidad e igualdad, vean la página 178 (Identity and equality) del libro Squeak By Example.

Finalmente, para hacer cosas con colecciones, vimos lo importante que son los  iteradores: #do:, #collect:, #select:, #detect:ifNone:, #reject: e #inject:into:

Les dejo la práctica 6, muy enfocada en Colecciones. Es una práctica muy importante porque les va a servir de apunte para estudiar.

Thursday, October 15, 2009

D+D Engine: Un engine 2d para el desarrollo de videojuegos.

Pruebas del engine: gestion de teclado, dibujado de primitivas, sprites, tileset etc...

Antes de empezar aclaremos la primer pregunta que puede surgir ya del titulo ¿Que es un engine?


Un engine: Un engine es una especie de Framework para el desarrollo de videojuegos, y cuyo objetivo(al igual que todo Framework) es facilitarnos el trabajo y poder enfocarnos de lleno a nuestro desarrollo y olvidándonos de algunas cuestiones básicas como la gestión de gráficos, sonido, entradas etc; usando algunas estructuras de datos y funciones (o clases) que guían al diseño de nuestra aplicación.

¿Y que tiene que ver esto con la programación O.O.? Sencillo, el engine del cual vamos a hablar es de un engine desarrollado con este paradigma, y que nace justamente para pasar de una API como SDL a un mundo de objetos.

Si nuevas preguntas… ¿Qué es una API? ¿Qué es SDL?


API: Una API en pocas palabras son un conjunto de módulos, funciones, o clases que permiten el acceso a otros componentes de software como puede ser una librería para la para la gestión de gráficos, o de un controlador de Wiimote por citar algunos ejemplos.

Y ahora se preguntarán, ¿Qué diferencia hay entre una API y un Framework? Es más sencillo de lo que parece, aunque a veces se las llega a confundir.

Las API´s son simplemente una interfaz a un componente de software, y nada más, es independiente de para que se use (EJ: desde un video juego hasta una bases de datos), y no afectan al diseño de nuestro programa.

Al contrario un Framework puede incluir el uso de muchas API´s, pero el mismo Framework ya cuenta con estructuras que afectan el diseño de nuestra aplicación, y están pensados para el desarrollo de aplicaciones especificas (EJ: o para videojuegos o para Base de datos).

Por su parte, SDL Es una API que proporciona las funciones básicas para realizar operaciones de dibujado, de gestión sonido, música, y carga y gestión de imágenes.

Con más conceptos en la cabeza les digo que a partir de SDL que esta programado en C, y por tanto en programación estructurada, diseñe e implemente un simple (muy simple y no concluido) engine 2d para el desarrollo de juegos en C++.

Ya existen otros como SMFL que hacen lo mismo y mejor, pero el objetivo era reinventar la rueda para aprender un poco.


Restan dos entradas que hablan de este desarrollo. En la que sigue les voy a contar la ventaja que supone pensar aplicaciones de este tipo en objetos, y en la última les voy a contar como se complica no tener un Garbage Recollector (como tiene smalltalk), ya que como dije el engine esta programado en C++ ( y este no lo tiene).


Espero les sea de interés.

Alejandro Iglesias.

Notas de la clase 5 y guía de trabajos prácticos

Hablamos de UML y vimos en detalle lo que vamos a usar de diagramas de clase. Recomiendo que consigan UML gota a gota. Si no lo consiguen, este articulo parece estar bastante actualizado.

Anteriormente habíamos hablado de diagramas de colaboración (o de comunicación como se los llama en UML 2.0). Aqui les dejo un link que les puede servir (ademas del libro)

Confirmamos que en Smalltalk las clases son objetos y por tanto entienden mensajes. Uno de los mensajes que entienden las clases es #new. Puedo definir otros mensajes de clase, y en particular nos interesan aquellos que reciben varios parámetros y nos devuelven una instancia completamente inicializada. Los llamamos complete creation methods.


En esta clase retomamos el tema de las cuentas y vimos que para aprovechar herencia debía ser posible extender métodos heredados (no solo redefinirlos). Para eso nos viene bien super. Al final de este post les dejo un mini-apunte sobre super y self.

Ya esta disponible la práctica 5. Tiene ejercicios de UML, super y self, métodos de clase y uso del debugger de Squeak.


self y super

selfsuper son pseudovariables. No se puede asignar objetos a estas variables. Es responsabilidad de la maquina virtual asegurarse de que cada vez que se ejecuta un método, selfsuper apuntan (referencian) al objeto correcto, es decir, al objeto que se encuentra ejecutando el método.

Primer lección importante: tanto super como self apuntan (referencian) al mismo objeto: el objeto que esta ejecutando el método.

self puede pasarse como parámetro en un mensaje, puede asignarse a una variable, y puede ser receptor de mensajes.

Cuando en un método veo "self hacerAlgo"  lo leo como "el objeto se envía #hacerAlgo a si mismo". Permite entre, otras cosas, refactorizar un metodo complejo, haciendo que el objeto se delegue tareas a si mismo que se resuelven en otro método (en este caso #hacerAlgo).

Cuando en un método veo "super hacerAlgo" lo leo "TAMBIEN" como el que el objeto se envía hacerAlgo() a "si mismo". Ya veremos la diferencia.

Cuando un objeto recibe un mensaje, no importa si se lo envió otro objeto o si se lo envió él a si mismo tratándose de "self". En ambos casos pasa lo mismo. Se inicia la búsqueda de un método en la clase del objeto y si no se encuentra en esa clase se sigue buscando siguiendo las relaciones de "hereda de".

Cuando un objeto recibe un mensaje que se envió él a si mismo, pero en lugar de referirse a si mismo como self, utilizósuper (p.e., self hacerAlgo) se cambia la forma en la que se comienza a buscar el método.
  • Cuando super recibe un mensaje, la búsqueda de método comienza en la clase superior a aquella donde está el método que envió el mensaje a super. Esto no es lo mismo que decir "en la superclase", o "en la superclase del objeto".
  • Esto es independiente de la clase de super/self.
Ese cambio el mecanismo de method lookup (busqueda de método) permite enviar nuevamente el mensaje cuyo metodo se esta definiendo al objeto receptor y evitar entrar en un ciclo infinito. Esto es útil para "EXTENDER" comportamiento heredado.

Ojo que en algunas definiciones de super equivocadamente dicen que la búsqueda de método comienza en la superclase del objeto receptor! Eso no es correcto.

Sunday, October 11, 2009

Algo sobre el Lenguaje Ruby (II)

En esta segunda entrega, veremos algo sobre estilos de código en Ruby, y luego algunos ejemplos de programación de objetos básicos en Ruby, basándonos en algunos TPs de la materia Programación III.

Estilos de código:

Hay varias cuestiones a tener en cuenta a la hora de programar en objetos en Ruby. Como en Smalltalk, se sigue la convención de que la clases se definen con mayúscula en la primer letra, las instancias y sus variables con minúscula, así como los métodos.

Las constantes se escriben todo en mayúscula.

La diferencia principal con el estilo “smalltalkero” es que los nombres con mas de una palabra se escriben de manera diferente: Mientras que en Smalltalk una variable o métodos se escribe estoEsElNombreClasicoDeUnaVariableSmalltalk, Ruby tiene por convención que sea esto_es_un_nombre_tipico_en_ruby.

Las convenciones son importantes, dado que todos los métodos, funciones, módulos, clases y demás cosas de las librerías se escriben siguiendo estas reglas, con lo cual, no adaptarnos a ellas puede traer problemas.

Un ultimo detalle es que algunos nombres de métodos en Ruby terminan con el signo '?'. Cada vez que un método termina con el signo de interrogación significa que retorna siempre verdadero o falso. En el caso que el método termine con '!', implica que el objeto al cual le enviamos el mensaje sera modificado. Es como una advertencia de alerta, por decirlo de alguna manera.

Implementaciones y pruebas referidas al TP 2 de Programación III en Ruby

Abrimos nuestro editor de textos preferido y copiamos lo siguiente:

class Persona

# Definimos getters
def get_nombre()
return @nombre
end

def get_apellido()
return @apellido
end

def get_dni()
return @dni
end

def get_padre()
return @padre
end

def get_madre()
return @madre
end

# Definimos setters
def set_nombre(nombre)
@nombre = nombre
end

def set_apellido(apellido)
@apellido = apellido
end

def set_dni(dni)
@dni = dni
end

def set_padre(padre)
@padre = padre
end

def set_madre(madre)
@madre = madre
end

end


Observemos que los getters y los setters son similares, y solo cambia la variable a la que esta definida. Existen métodos dentro de Ruby que permiten automatizar la creacion de setters y getters. Ellos son:

attr_reader: Para creación de getters
attr_writer: Para creación de setters
attr_accessor: Para creación de getters y setters

El código anteriormente presentado se reduciría al siguiente

class Persona
attr_accessor :nombre, :apellido, :dni, :padre, :madre
end

Con esta ultima implementación abrimos un interprete interactivo (irb) y hacemos algunas pruebas(En negrita las lineas ingresadas por el usuario):

$ irb
irb(main):001:0> require 'Personas_con_accesors'

=> true
irb(main):002:0> p = Persona.new()

=> #
irb(main):005:0> p.methods

=> ["inspect", "tap", "clone", "public_methods", "__send__", "object_id", "instance_variable_defined?", "apellido", "equal?", "freeze", "extend", "apellido=", "send", "methods", "hash", "dup", "to_enum", "instance_variables", "dni", "eql?", "instance_eval", "id", "dni=", "singleton_methods", "taint", "enum_for", "frozen?", "instance_variable_get", "instance_of?", "padre", "display", "to_a", "method", "type", "padre=", "instance_exec", "protected_methods", "==", "===", "instance_variable_set", "kind_of?", "madre", "respond_to?", "to_s", "class", "madre=", "private_methods", "=~", "tainted?", "__id__", "nombre", "untaint", "nil?", "is_a?", "nombre="]
irb(main):010:0> p.public_methods(false)

=> ["padre", "madre=", "nombre=", "dni", "padre=", "apellido", "dni=", "madre", "nombre", "apellido="]
irb(main):011:0> p.nombre="Ana"

=> "Ana"
irb(main):012:0> p.apellido="Garcia"

=> "Garcia"
irb(main):013:0> p.dni=33221256

=> 33221256
irb(main):014:0> p.nombre

=> "Ana"
irb(main):015:0> p2 = Persona.new

=> #
irb(main):016:0> p2.nombre="Jose"

=> "Jose"
irb(main):017:0> p2.apellido="Taringa"

=> "Taringa"
irb(main):018:0> p.padre=p2

=> #
irb(main):019:0> p.inspect

=> "#>"
irb(main):020:0> exit

$

Hemos visto hasta aquí la implementación de métodos y clases en sus formas básicas.

Pasemos a definir ahora un método para inicializar el objeto. Sabemos que el método para inicializar un objeto es una función que asigna a las variables de instancia los valores adecuados para que el objeto funcione en el sistema sin problemas. Como todas las variables sin valor se inician con nil, sabemos que no es conveniente para operar, siempre es conveniente tener un mensaje de inicialización de los objetos.

class Persona

attr_accessor :nombre, :apellido, :dni, :padre, :madre

def initialize(nombre, apellido, dni, padre="", madre="")
@nombre = nombre
@apellido = apellido
@dni = dni
@padre = padre
@madre = madre
end
end

Un dato interesante es que el método initialize es automáticamente invocado cuando le enviamos el mensaje new a la clase. No debemos preocuparnos por la inicialización de los objetos una vez que implementamos el método de inicialización.

Si observamos la cabecera del método de inicialización

def initialize(nombre, apellido, dni, padre="", madre="")

vemos que padre y madre se asignan con cadenas vacías. Lo que estamos haciendo es asignar valores por defecto a esas dos variables. O sea, nombre, apellido y dni son obligatorios para crear un objeto de la clase Persona, pero padre y madre son opcionales.

$ irb
irb(main):001:0> require 'Personas_con_accesors_y_mensaje_de_inicializacion'

=> true
irb(main):002:0> p = Persona.new("Jose", "Taringa", 23456876)

=> #
irb(main):003:0> p.padre

=> ""
irb(main):004:0> p2 = Persona.new("Pedro", "Taringa", 14678384)

=> #
irb(main):005:0> p.padre= p2

=> #
irb(main):006:0> p.inspect()

=> "#>"
irb(main):007:0> exit

$

Por ultimo, observemos que la sentencia require se utiliza para importar módulos. Lo que va entre comillas simples es el nombre del archivo que desea importarse. Si encuentra un archivo con ese nombre en la carpeta local, lo carga (como en nuestro ejemplo), sino, busca en la librería estandar de Ruby. Si tampoco lo encuentra allí, lanza un error.

Recursos:

http://www.ruby-lang.org/es/documentation/quickstart/

http://tryruby.hobix.com/

Saturday, October 3, 2009

Algo sobre el Lenguaje Ruby (I)

Buenas a todos. A invitación de Alejandro, este es el primero de una serie de posts acerca de Ruby, un lenguaje interpretado y orientado a objetos que por varios motivos a cobrado renombre y se extendió su uso en el ultimo tiempo. Veamos de que se trata.

¿Que es Ruby?

Ruby es un lenguaje de alto nivel, interpretado, dinámico, de código abierto y orientado a objetos. Su autor, Yukihiro Matsumoto (Matz), se inspiro en lenguajes como Python, Perl, Lisp, Smalltalk y Eiffel, entre otros.

El lenguaje en si es un programa interprete y gran numero de bibliotecas que proveen todo tipo de funcionalidades aptas para ser usadas en desarrollo de sistemas profesionales, educativos y académicos.

Características:

  • Alto nivel: "Los lenguajes de programación de alto nivel se caracterizan por expresar los algoritmos de una manera adecuada a la capacidad cognitiva humana, en lugar de a la capacidad ejecutora de las máquinas"[1].

  • Interpretado: No es necesario un proceso de compilación. Existe un programa, llamado intérprete, el cual es invocado en el momento que se desea ejecutar un programa. Este intérprete va ejecutando cada una de las acciones programadas mediante un proceso de conversión de código Ruby a código entendible por la maquina. El proceso de interpretación se realiza a medida que se necesita ejecutar una instrucción.

  • Dinámico: Las variables en un mismo programa pueden tomar valores de diferentes tipos de datos. Si bien no es obligatorio, la gran mayoría de los lenguajes dinámicos son interpretados.

  • Software libre y código abierto: El interprete y las bibliotecas tienen una doble licencia: GPL y Ruby (Software libre y código abierto respectivamente).

  • Orientado a Objetos: Paradigma de la programación que usa estructuras conocidas como objetos, y las vincula de una manera especifica (mensajes) para establecer la construcción de un programa o sistema. La unidad mínima del paradigma es el “Objeto”, una entidad que reúne conocimiento y comportamiento. Un objeto provee un grupo de mensajes al “resto del mundo” (otros objetos) para interactuar con ellos. Los objetos se envían mensajes entre si, y dichos mensajes se vinculan con métodos específicos que implican una secuencia de acciones a realizar.

  • Multiparadigma: Se entiende con esta denominación, a toda una gama de lenguajes que permiten programar en un mismo momento en varios paradigmas de programación. Por ejemplo, usar estructuras de iteración como el while, y en otras partes del mismo programa usar objetos. Ruby es uno de los lenguajes que permite programar combinadamente en varios paradigmas de programación.

Posee una sintaxis muy similar a Python y Perl, con lo cual comenzar a trabajar con el lenguaje es muy intuitivo, pero también sirve para desarrollos avanzados.

Por ejemplo, el primer programa que podemos hacer con Ruby:

puts “hola mundo”

Si escribimos el texto anterior en un archivo, lo guardamos como “hola.rb” y desde una terminal escribimos:

$ ruby hola.rb
hola mundo
$

Como prerrequisito, se debe tener instalado el interprete Ruby y las bibliotecas del Lenguaje, el cual se descarga gratuitamente desde internet y esta soportado en diversas plataformas de desarrollo (Windows, Linux, etc...)

El interprete interactivo vs. el Workspace

Si se esta acostumbrado a trabajar en Smalltalk y su workspace, a la hora de desarrollar con Ruby se extrañara un lugar donde hacer pruebas paso a paso de un grupo de sentencias. Una solución a esto es el interprete interactivo llamado irb, el cual nos provee una interfaz para ejecutar código Ruby en el momento, y nos provee un entorno de trabajo temporal para realizar pruebas y pequeñas tareas.

Las diferencias entre el interprete interactivo y el workspace, es que en el primer caso se usa para tests y desarrollos puntuales menores, en cambio, el segundo se concibe como el ambiente donde una vez que todo funcione, quedara la aplicación definitiva. El workspace tiene además herramientas de debugging y toda una gama de aplicaciones que lo hace mucho mas completo. El interprete interactivo, por el contrario, provee por si mismo contadas instrucciones propias y facilita el ingreso de código y su evaluación.

Una sesión en el interprete interactivo[2]:

$ irb
irb(main):001:0> "Hola mundo"
=> "Hola mundo"
irb(main):002:0> puts "Hola mundo"
Hola mundo
=> nil
irb(main):003:0> 5 + 4
=> 9
irb(main):004:0> 5 * 5
=> 25
irb(main):005:0> Math.sqrt(9)
=> 3.0
irb(main):006:0> a = 3 ** 2
=> 9
irb(main):007:0> b = 4 ** 2
=> 16
irb(main):008:0> Math.sqrt(a+b)
=> 5.0
irb(main):009:0> Math.methods
=> ["private_class_method", "inspect", "name", "tap", "sinh", "clone", "public_methods", "__send__", "object_id", "method_defined?", "instance_variable_defined?", "exp", "equal?", "freeze", "acos", "extend", "ldexp", "send", "const_defined?", "methods", "instance_method", "ancestors", "module_eval", "hash", "tanh", "dup", "autoload?", "instance_variables", "to_enum", "atan2", "instance_methods", "public_method_defined?", "log", "class_variable_defined?", "eql?", "constants", "asin", "id", "instance_eval", "hypot", "singleton_methods", "module_exec", "const_missing", "acosh", "taint", "instance_variable_get", "frozen?", "enum_for", "private_method_defined?", "cos", "public_instance_methods", "display", "instance_of?", "log10", "method", "to_a", "included_modules", "atan", "const_get", "instance_exec", "type", "erf", "<", "protected_methods", "<=>", "class_eval", "==", "asinh", "class_variables", ">", "===", "instance_variable_set", "sin", "protected_instance_methods", "protected_method_defined?", "respond_to?", "kind_of?", "sqrt", ">=", "public_class_method", "to_s", "<=", "cosh", "const_set", "class", "erfc", "private_methods", "=~", "tainted?", "__id__", "class_exec", "autoload", "atanh", "untaint", "nil?", "private_instance_methods", "tan", "include?", "is_a?", "frexp"] irb(main):010:0> quit
$

El interprete es una gran herramienta para los desarrolladores, dado que permite ejecutar porciones de código mostrando sus resultados. Al igual que en Python, el uso del interprete interactivo a permitido a programadores elevar de manera notable la productividad, pues se realizan depuraciones parciales de código a medida que se tienen dudas sobre el mismo. Esto reduce la fase de depuración final que ocurría en los desarrollos con lenguajes estáticos.

Notas al pie:

[1]: http://es.wikipedia.org/wiki/Lenguaje_de_alto_nivel
[2]: Ejemplo extraído en su mayoría de http://www.ruby-lang.org/es/documentation/quickstart/