domingo, 12 de diciembre de 2010

¡Habemus Blog!

El nuevo blog gitevangelism se dedica a la promocion de GIT. Un sistema de versionamiento que tiene asombrosos features pero que lamentablemente no esta lo bastante
difundido, por lo menos en los ambientes que frecuento: en los trabajos y en la facultad.

Sin duda, el sistema de control de versiones mas usado y difundido es el SVN, son muy pocas personas las que conocen a fondo las prestaciones de ambos como para poder elegir y por eso podria parecer que lo unico que agrega GIT son "commits locales" y "complejidad innecesaria". gitevangelism se encargara (entre otras cosas) de desmistificar esto y promover el conocimiento acerca de esta herramienta y como el control de versiones esta mas asociado a la forma del proceso de desarrollo de lo que en principio se cree.

El nuevo blog:
http://gitevangelism.blogspot.com

--amend

martes, 24 de agosto de 2010

Overview de herramientas UML online

Resulta que me anote en una materia interesante y estoy necesitando encontrar una herramienta de UML a mano, facil y si es posible colaborativa... esto es online, o "en la nube"

Ya que estoy probando varias opciones, aprovecho para escribir un overview de todas las herramientas que probe. Para cada herramienta se incluye un diagrama generado con esta y la evaluacion de las siguientes caracteristicas:

* Almacenamiento: Si tiene storage para almacenar los diagramas online
* Vistas: Si tiene vistas publicas dinamicas para que se pueda mostrar en una pagina o en un blog la ultima version del diagrama
* Diagramas: Que tipos de diagramas se pueden hacer (diagramas de actividad, casos de uso, clases, objetos, secuencia, despliegue, colaboracion, transicion, componentes)
* Exports: Si se puede exportar como imagen o como algun otro formato editable
* Imports: Si se puede importar imagenes o incluso otros objetos
* Coop: Si es colaborativo, o sea, si varios usuarios pueden editar el diagrama simultaneamente diseñando de manera cooperativa.
* Estabilidad: Si es posible editar sin que se cuelgue o tenga algun otro fallo que afecte el trabajo
* Portabilidad: Si funciona en varios navegadores (por ahora testeados en Mozilla Firefox 3.6.8 con Ubuntu Linux)
* Registracion: Si es necesaria, y que implica
* Costo: Si tiene paquetes de uso gratis, si tiene paquetes de servicio pago, que limitaciones y precios hay de cada uno de ellos
* Engine: Como funciona, si usa java, flash, etc...

Cacoo
http://cacoo.com/

Segun mi opinion, uno de los mejores, si se pudiera guardar el diagrama en la computadora local seria perfecto

* Almacenamiento: SI
* Vistas: SI (ej: https://cacoo.com/diagrams/hB18F3rQnjWqxQ74/view )
* Diagramas: casos de uso, clases, secuencia, estados, componentes, deployment, ER y tiene mas bibliotecas de objetos
* Exports: Solo imagenes en formato PNG (la version gratuita)
* Imports: Cualquier tipo de imagen
* Coop: SI
* Estabilidad: Si tenes una conexion mala no lo uses
* Portabilidad: Funciona bien en firefox 3.6.8 y en Ubuntu Linux
* Registracion: SI o SI es necesaria (tambien con la version gratuita)
* Costo: Gratis (limitacion de 3 colaboradores por diagrama)
Engine: flash

Creatly
http://creatly.com

Este diagramador puede guardar archivos en la computadora local (ademas de poder guardarlos online)

* Almacenamiento: SI
* Vistas: SI
* Diagramas: Actividad, Clase, Colaboracion, Componentes, Deployment, ER, Objetos, Secuencia, Estados, Casos de uso, networking, electronica, de flujo
* Exports: PNG, JPG, PDF, Creatly File
* Imports: Image, Creatly File
* Coop: SI
* Estabilidad: Me colgo el firefox una vez, pero la mayoria de las veces lo pude usar
* Registracion: Se puede usar sin registracion (aunque se recomienda registrarse y es gratuito)
* Costo: Actualmente Gratis para 2 collaborators, U$S4.95 para 5 collaborators y un 1 Gb, U$S9.95 para ilimitado espacio y collaborators. No se puede tener varios proyectos ni exportar archivos en formato "editable" en la version gratuita. Ver http://creately.com/plans7

yUML
http://yuml.me/

Este es rarisimo, hay que poner un codigo (como una especie de lenguaje) y genera el diagrama. No tiene editor y es el que menos funcionalidades tiene, lo unico bueno que tiene es que funciona bien sin impotar cual sea el browser

* Almacenamiento: NO
* Vistas: NO (Algo parecido)
* Diagramas: clases, actividad, casos de uso
* Exports: Imagen PNG
* Imports: NO
* Coop: NO
* Estabilidad: 100% Siempre funciona, porque es muy sencillo
* Portabilidad: 100%, ya que no importa que browser uses, el diagrama se genera del lado del servidor a partir del "codigo" que se le ingrese
* Registracion: no hay
* Costo: Gratis

gliffy
http://www.gliffy.com/

Este es interesante, tiene el estilo del cacoo y al creatly, pero viene con templates base para crear diagramas (con lo que ayuda bastante al usuario primerizo), lastima que no me anda el drag&drop (¿sera mi version de flash?), cualquier cosa pruebenlo (no se necesita registracion para probar). En lo personal para lo que necesito no tiene elementos de suficientes diagramas.

* Almacenamiento: SI
* Vistas: SI (Ej: http://www.gliffy.com/pubdoc/2214754/S.png)
* Diagramas: Diagramas de flujo, networks, ER, UI, Diagramas de clases, secuencia, casos de uso
* Imports: SI, Formatos GIF, JPEG y PNG
* Exports: SVG(Visio), Gliffy Xml, Formatos graficos JPEG y PNG
Coop: SI
* Estabilidad: Por lo visto es estable, pero no lo pude probar bien
* Portabilidad: Me fallo en firefox 3.6.8 con Ubuntu Linux, talvez funcione en otras plataformas
* Registracion: Se puede usar sin registracion (aunque se recomienda registrarse y es gratuito)
* Costo: es Gratis, pero es un trial de 30 dias

gModeler
http://www.gskinner.com/gmodeler/

Mismo problema de drag&drop como con gliffy, mas tarde probare este y otros con otro entorno.

* Almacenamiento: NO (Aunque permite guardar como XML localmente)
* Coop: NO
* Portabilidad: MALA, no funciono en firefox 3.6.8 con Ubuntu Linux
* Registracion: no hay
* Costo: es totalmente Gratis

Mas tarde voy a probar gModeler desde otro entorno

Enlaces:

Cacoo: http://cacoo.com
Creatly: http://creatly.com
yUML: http://yuml.me/
gliffy: http://www.gliffy.com/
gmodeler: http://www.gskinner.com/gmodeler/

jueves, 19 de agosto de 2010

Diagramas UML online



Visiten esta web:

http://yuml.me/

Permite crear diagramas UMLs online usando un lenguaje bastante interesante, no tuve mucho tiempo para probarlo mas que para hacer este diagrama que les estoy mostrando

lunes, 16 de agosto de 2010

La magia del TDD: un ejemplo real en ruby

Este fin de semana comence un proyecto, una nueva gema que "desparsea" los arboles generados por la gema ParseTree. Explicar los detalles de ese proyecto no es el tema de este articulo, sino mas bien contar la experiencia con TDD.

Para los que no saben que es TDD la wikipedia explica. Sin son vagos como para clickear el link, TDD es una metodologia que basicamente tiene dos pilares: "write tests first" (escribir los test primero) y "refactoring".

Resulta que lo que estoy desarrollando consiste en una funcion que revierte o encuentra la preimagen de otra funcion (es decir, genera un string con codigo ruby que resulte en un determinado arbol cuando se parsee con ParseTree).

Este requerimiento tiene un grado muy alto de testeabilidad ya que se puede calcular el input correspondiente a partir del output esperado (seria como el testeo oracle, pero al revez porq estamos buscando hallar la inversa de una funcion que ya tenemos, que es ParseTree)

Manos a la obra:

Paso 1) Escribir los tests primero:
http://github.com/tario/unparse_tree/tree/0ca29f14

En este caso se fue desarrollando de manera de ahorrar lineas y probar *todos* los casos (mas adelante se sabe que se omitieron algunas cosas, pero creo q eso es comun en TDD sobre todo cuando el analisis de cobertura no es viable)

Paso 2) Implementar hasta que todos los tests pasen:
http://github.com/tario/unparse_tree/tree/48c9a997

Cambios hasta que funcione, algunos "harcodean" o ponen "magic values", otros agregan funcionalidad a conciencia, lo importante es que cada commit disminuye el numero de errors + failures reportados y no se modifican los tests

Paso 3) Refactoring:

En esta etapa se modificara el codigo hasta que se vea minimamente "bien", es decir, se eliminara codigo duplicado, se implementaran las cosas "de verdad" en lugar de usar "magic values", "harcodeos" o "if extraños" y cualquier cambio que mejore el diseño/la distribucion del codigo, de mas esta decir que por cada cambio todos los tests siempre tienen que pasar. Todavia no alcance esta etapa en el proyecto... ya llegara.

Paso 4) Vuelta al paso 1:

Con nuevos requerimientos y/o bugs encontrados, se genera una nueva bateria de tests y el ciclo vuelve a comenzar.

De todo esto, en la practica me encuentro con las siguientes ventajas de usar TDD:

* La validacion de si el codigo funciona es automatica, con solo ejecutar un comando puedo saber si "rompi" el codigo o si estoy progresando
* TDD guia a escribir el codigo de manera "correcta" o por lo menos mas prolija
* Se puede testear un numero mas grande de casos, con lo que se cubren mayor cantidad de posibilidades

Y, como todo, tiene sus desventajas (aunque se mitigan y son evidentamente superadas por las ventajas)

* Hay que programar las pruebas que si no se usara TDD, no se tendrian que programar (de todas maneras, con o sin TDD siempre hay que testear el software, y sin TDD se hace de forma manual)
* Las pruebas no garantizan cobertura total, es decir, pueden ser %100 exitosas las pruebas y el software fallar en la practica al haber omitido algo (esta claro que la idea en principio no es confiar ciegamente en las pruebas, mas bien TDD tiene que basarse en la construccion de pruebas)
* Durante la fase de desarrollo, me doy cuenta de errores que se ven en el codigo o al escribir el codigo, pero no puedo corregirlos si no existen tests que pasen como resultado de esa correccion (para resolver esto se puede optar principalmente por dos alternativas, una seria registrar como un "ticket" la necesidad de agregar el test para el proximo ciclo, la otra seria agregar el test en ese mismo momento, aunque eso se alejaria del espiritu del TDD y superpondria los pasos 1 y 2)

Cabe destacar que las ventajas del TDD asi como otras metodologias son apreciables a mediano y largo plazo (TDD mas que otras), ya que a medida que avancen los ciclos de TDD, los tests desarrollados en ciclos anteriores cumpliran el rol de automatizar las regresiones, es decir, que si se modifica el codigo en un proyecto que tiene 8 meses de vida, las pruebas automaticas rebelaran si se rompio funcionalidad implementada al principio del proyecto, tres meses atras, dos meses atras, que implemento otra persona, etc...
Despues de varias iteraciones, volvere a postear para hacer un analisis de las ventajas de TDD a largo plazo

Enlaces

http://en.wikipedia.org/wiki/Test-driven_development
http://github.com/tario/unparse_tree/tree/0ca29f14 (tests creados en el primer ciclo de unparse_tree)
http://github.com/tario/unparse_tree

martes, 10 de agosto de 2010

martes, 22 de junio de 2010

Sandbox de codigo ruby (remake 2010)



Anteriormente en este mismo blog anuncie la creacion de un sandbox para ruby. Ese proyecto se cancelo y quedo definitivamente incompleto. El proyecto se llamaba arena-ruby-sandbox.

Hace un tiempo comenze el desarrollo de un nuevo sandbox (llamado shikashi), pero con un diseño y una idea totalmente distinta: mientras arena-ruby-sandbox es un intento de sandbox en codigo ruby puro, shikashi se implementa utilizando una modificacion al interprete de ruby hecha en C en formato de extension (llamada rallhook).

Funciona mejor que su antecesor ademas de permitir usar casi todos los elementos del lenguaje como clases y metodos singleton cosa que arena-ruby-sandbox no permitia.

Recientemente libere la version 0.7.1 de rallhook ademas de la version 0.1.0 del sandbox shikashi. La documentacion del gem (que incluye instrucciones de como instalarlo, ejemplos de uso y descripcion completa del API) esta en http://tario.github.com/shikashi/doc/

NOTA: tambien se puede instalar haciendo

gem install shikashi

Cosa que no menciona el README y lo actualizare en proximos releases.

sábado, 19 de junio de 2010

Post-mortem debugging en linux


Que es el debugging post-mortem

El debugging post-mortem es una clasica tecnica de debugging que consiste en que el sistema operativo genera un volcado completo de los registros, los threads y la memoria de un proceso que termina de manera anomala (ya sea por SIGSEGV o por SIGABRT), en linux estos volcados se llaman "cores" y se pueden examinar con gdb para ver en que punto del codigo ocurrio el error, los threads con sus backtraces, los registros, e incluso el valor de las variables (si se tiene informacion de debug) en el momento en que termino el proceso.

Como activarlo

Por default, en la mayoria de los sistemas linux viene desactivado, pero activarlo es tan simple como ejecutar en la terminal:

ulimit -c 4000000000

Que determina que el limite maximo para el tamaño del core sera de aproximadamente 4Gb (valores mucho mayores pueden ser rechazados a no ser que se tenga privilegios de root).

Esto solo tiene validez en la shell en la que se activo, si se necesita que este siempre activo para cualquier sesion, se podria agregar la linea "ulimit -c 4000000000" al final del archivo ~/.bashrc

echo ulimit -c 4000000000 >> ~/.bashrc

Como verlo funcionando

Se crea un programa de purebas, "mytest.c" que genera un error abort()

#include "stdlib.h"

int main() {
abort();
}


Se compila generando informacion de debug y se ejecuta:

gcc -ggdb mytest.c -o mytest
./mytest

El programa falla y seguramente anunciara que se genero el core (en mi caso solamente el archivo generado se llama "core", en algunos sistemas pone el pid o cosas asi)

Se puede usar gdb para analizar el core, tambien hay que pasarle como parametro el ejecutable que genero el core para poder ver la informacion de debug:

gdb -c core mytest


A partir de entonces se puede examinar el estado que tenia el programa en el momento de finalizar como si se tratara de un debug normal:

(gdb) bt
#0 0x00007f55e7ef3a75 in raise () from /lib/libc.so.6
#1 0x00007f55e7ef75c0 in abort () from /lib/libc.so.6
#2 0x000000000040052d in main () at mytest.c:4
(gdb) info threads
* 1 Thread 4352 0x00007f55e7ef3a75 in raise () from /lib/libc.so.6
(gdb) disass main
Dump of assembler code for function main:
0x0000000000400524 <+0>: push %rbp
0x0000000000400525 <+1>: mov %rsp,%rbp
0x0000000000400528 <+4>: callq 0x400418
End of assembler dump.
(gdb) print/x $rcx
$4 = 0xffffffffffffffff
(gdb)

viernes, 18 de junio de 2010

Deshacer el push en git

Actualizacion: Quick fix

Alguien pusheo commits que no debia, o por alguna razon se pretende "deshacer" commits que ya se enviaron al servidor central.

Quick fix

Buscar el commit a donde se pretende volver: (usar git log o git reflog, etc...), y despues hay que ejecutar estos commandos (donde a_donde_volver se reemplaza por el commit):


git reset a_donde_volver
git checkout HEAD .
git push --force


Y a trabajar

NOTA: usar --force solo para casos especificos como este, ya que directamente sobreescribe cambios en la rama remota (que es lo que se pretende hacer en este caso)

Narrado (for dummys)

Todo lo que voy a explicar es asumiendo que se esta trabajando en la rama master (que es la default en git), si no estas trabajando en la rama master, el comando "git branch" muestra la rama de trabajo en la que estas trabajando

Antes, que nada, se puede hacer un tag del master actual:

git tag ultimo_master master


Posteriormente, hay que encontrar el commit al cual se quiere volver, se pueden revisar los logs (el nombre de la rama es opcional, si no se indica usa la rama de trabajo actual):

git log [master]


Supongamos que el commit al que se quiere volver es 0123456789abcd..., puede ser util taguearlo para referenciaro facilmente mas adelante (aunque se puede hacer todo referenciando al commit, directamente)


git tag a_donde_volver 0123456789abcd...


Posteriormente, se hace un reset a para que la rama master local referencie a ese commit, y despues un checkout para cambiar los archivos y que coincidan


git reset a_donde_volver
git checkout HEAD .


Despues, hay que sobreescribir la referencia master remota con la actual, pero hay que usar --force para que git no verifique si se trata de un fast-forward (porque sino rechaza la operacion), recordar usar --force solamente en casos especificos como este.


git push --force


Y despues se puede seguir trabajando normalmente

Bonus track

Puede ser util crear un branch en el servidor a partir del master original antes de que se revierta (para poder analizarlo entre todos, etc...), para hacer esto:


git push origin ultimo_master:refs/heads/old_master


Y en este post explico como usar los branches:

http://nilclass.blogspot.com/2009/08/branches-remotos-en-git.html

miércoles, 16 de junio de 2010

Solucion a sectores dañados en linux. EXT2 y EXT3

Sintomas

El sistema se cuelga en tareas estupidas como reproducir una pelicula, instalar paquetes, configurar cosas, abrir determinados archivos para despues de un tiempo de estar "colgado" anunciar que hasta la tarea mas simple fallo por un "I/O error".

Hace falta confirmarlo tambien con los logs, la informacion necesaria aparece en el syslog (en /var/log/syslog ), se encontraran lineas similares a estas:


Jun 16 16:17:56 ubuntu kernel: [ 6193.840250] Buffer I/O error on device sda1, logical block 155153547
Jun 16 16:17:56 ubuntu kernel: [ 6193.840254] Buffer I/O error on device sda1, logical block 155153548
Jun 16 16:17:56 ubuntu kernel: [ 6193.840258] Buffer I/O error on device sda1, logical block 155153549


O tambien de estas:

Jun 15 20:16:01 ubuntu kernel: [ 25.636424] ata1.00: status: { DRDY ERR }
Jun 15 20:16:01 ubuntu kernel: [ 25.640935] ata1.00: configured for UDMA/133
Jun 15 20:16:01 ubuntu kernel: [ 25.640951] ata1: EH complete
Jun 15 20:16:01 ubuntu kernel: [ 29.172011] ata1.00: exception Emask 0x0 SAct 0x7fff SErr 0x0 action 0x0
Jun 15 20:16:01 ubuntu kernel: [ 29.172013] ata1.00: irq_stat 0x40000008
Jun 15 20:16:01 ubuntu kernel: [ 29.172016] ata1.00: failed command: READ FPDMA QUEUED
Jun 15 20:16:01 ubuntu kernel: [ 29.172022] ata1.00: cmd 60/08:28:a7:74:3f/00:00:09:00:00/40 tag 5 ncq 4096 in
Jun 15 20:16:01 ubuntu kernel: [ 29.172025] ata1.00: status: { DRDY ERR }
Jun 15 20:16:01 ubuntu kernel: [ 29.176722] ata1.00: configured for UDMA/133
Jun 15 20:16:01 ubuntu kernel: [ 29.176740] ata1: EH complete
Jun 15 20:16:01 ubuntu kernel: [ 32.440790] ata1.00: exception Emask 0x0 SAct 0x7fab SErr 0x0 action 0x0
Jun 15 20:16:01 ubuntu kernel: [ 32.440792] ata1.00: irq_stat 0x40000008
Jun 15 20:16:01 ubuntu kernel: [ 32.440795] ata1.00: failed command: READ FPDMA QUEUED
Jun 15 20:16:01 ubuntu kernel: [ 32.440801] ata1.00: cmd 60/08:48:a7:74:3f/00:00:09:00:00/40 tag 9 ncq 4096 in
Jun 15 20:16:01 ubuntu kernel: [ 32.440805] ata1.00: status: { DRDY ERR }
Jun 15 20:16:01 ubuntu kernel: [ 32.440807] ata1.00: error: { UNC }
Jun 15 20:16:01 ubuntu kernel: [ 32.445770] ata1.00: configured for UDMA/133
Jun 15 20:16:01 ubuntu kernel: [ 32.445785] ata1: EH complete


Solucion

Si algunos sectores del disco estan dañados sera inevitable que se pierda el disco entero tarde o temprano, por eso lo primero que se debe hacer es backup de toda la informacion.
Posteriormente, para poder seguir usando el disco, se debe hacer una revision completa marcando los bloques dañados como tal, el comando que hay que ejecutar es:


e2fsck -c /dev/sda1


Reemplazando /dev/sda1 por la particion que tengan que reparar.

Esto solo se puede hacer con la particion desmontada, para poder hacerlo asi recomiendo una de tres opciones:

1) Usar un live-cd como los de ubuntu, que les permite acceder a las particiones, tienen los comandos basicos y hasta entorno grafico para que puedan, por ej, escribir articulos en su blog publicando la solucion (es mi caso)

2) Usar una opcion de "rescue" (no estoy seguro si viene con ubuntu, pero viene con todos los fedora) eso les da una shell con privilegios de root pero nada de graficos, de ventanitas de gelatina, ni menos cubos de escritorio girando

3) Inician el sistema normalmente, y con Ctrl+Alt+F1 pasan a la consola sin graficos, ejecutan:


sudo init 1


Para pasar a runlevel 1 que detiene todos los servicios (incluyendo el entorno grafico) y permite desmontar cualquier particion, ahi ejecutan el escaneo y cuando termine vuelven a montar la particion y hacen


sudo init 5


Para volver a runlevel 5

Esta ultima es mas para "hackers" pero es innecesariamente complicada y me fracture el dedo indice cuando quise hacerla.

domingo, 13 de junio de 2010

Renovado diseño del blog

Tarde de domingo sin saber que hacer, renovacion visual del blog. Se hicieron los siguientes cambios.

* Se cambiaron los colores blancos, claros de blogs de psicologia newbies por colores darks, bizarros propios del underground, el H4X0R1NG, el KRAK0RING y PRHEKIRING aunque el blog NO PUBLICARA ARTICULOS DE ESA CATEGORIA :P (para eso hay blogs muy buenos en la web)

* Se cambiaron los colores del syntax highlighting en el style para que tenga sentido con los nuevos colores (todo dark) y se incluyo el style como tag en el template del blog para acelerar la carga de la pagina

* Se incluyeron todos los Javascripts de highlighting en el template del blog (en los tags ) en lugar de que sean referencia remota al sitio donde estaban alojados, con esto se acelera por mucho la carga de la pagina.

* Se cambio el fondo por uno de esos fondos "geeks" que hay en las opciones, pero como esto es ruby, se pinto de rojo (el original era azul)

Lo que mas me ayudo fue el plugin firebug para probar como quedan los colores antes de grabar en el template, y analizar un poco el source code de la pagina.
Tambien me sirvio bastante el irb para escapear el javascript, la libreria CGI:


require "cgi"
CGI.escapeHTML("<script>alert('hello world')</script>");
# => "&lt;script&gt;alert('hello world')&lt;/script&gt;"


Espero que la experiencia blogger sea mas ruby ahora

sábado, 29 de mayo de 2010

Definicion de clases y metodos en un eval

Una de las miles de cualidades que tiene ruby como lenguaje dinamico es la ejecucion de codigo ruby contenido en un string mediante el uso de la funcion eval.
Asi se pueden hacer cosas bastante interesantes ejecutando codigo ingresado dinamicamente ^_^
No obstante es necesario conocer como sortear determinados obstaculos en la ejecucion de codigo dinamico


class Runner
def run(code)
eval(code)
end
end

runner = Runner.new

# ¡¡FAIL!! :(, no se puede definir classes desde adentro de un metodo (Runner#run)
runner.run("
class X
def foo
print \"hello world\n\"
end
end

x = X.new
x.foo
")



Lo que se intento hacer en el ejemplo anterior, para el interprete es equivalente a:


class Runner
def run(code)
# いけない!!!
# en ruby no esta permitido definir clases adentro de metodos
# (aunque si permite hacer otras cosas locas XD )
class X
def foo
print \"hello world\n\"
end
end

x = X.new
x.foo
end
end


Para poder hacerlo correctamente hay que pasarle un segundo parametro a eval que es el "binding", un binding representa el contexto en ruby de donde se llama el binding, que incluye las variables locales, etc... mejor verlo en el ejemplo que explicarlo:


class Runner

class << self
attr_accessor :runner_binding
end

def run(code)
# se especifica un binding al eval para definir el contexto
# en el que se ejecuta el codigo
eval(code, Runner.runner_binding)
end
end

# se copia el binding del contexto actual (fuera de cualquier clase o metodo)
Runner.runner_binding = binding

runner = Runner.new

# se puede definir clases en el codigo pasado a eval, porque el binding
# esta afuera de cualquier declaracion de clase o metodo y el eval se
# llama con ese binding
runner.run("
class X
def foo
print \"hello world\n\"
end
end

x = X.new
x.foo
")




Que para el interprete es lo mismo que reemplazar el codigo en donde se llama a binding en lugar de en donde se llama a eval:


class Runner

class << self
attr_accessor :runner_binding
end

def run(code)
# se especifica un binding al eval para definir el contexto
# en el que se ejecuta el codigo
eval(code, Runner.runner_binding)
end
end

# よろしい
# Runner.runner_binding = binding
class X
def foo
print \"hello world\n\"
end
end

x = X.new
x.foo




Y ya que estamos, les cuento que otra cosa tiene el eval para hacer


def bar
1/0 # ZeroDivisionError
end

def foo(code) # ¿porque siempre foo?
eval(code)
end

foo("bar") #


Resultado:


test.rb:6:in `foo': test.rb:2:in `/': divided by 0 (ZeroDivisionError)
from test.rb:2:in `bar'
from (eval):1:in `foo'
from test.rb:9:in `eval'
from test.rb:6:in `foo'
from test.rb:9



Mejor, pasarle unos argumentos adicionales a eval especificando el "archivo" y el numero de linea de donde viene el codigo evaluado


def bar
1/0 # ZeroDivisionError
end

def foo(code) # ¿porque siempre foo?
eval(code, binding, "foo_eval.rb", 1)
end

foo("bar") #


Resultado:


test.rb:2:in `/': divided by 0 (ZeroDivisionError)
from test.rb:2:in `bar'
from foo_eval.rb:1:in `foo'
from test.rb:6:in `foo'
from test.rb:9


Ahora se puede ver mejor en el backtrace de donde viene el codigo, con esto mejorada la trazabilidad cuando se usa eval.

jueves, 6 de mayo de 2010

¡Cuidado! Pizza Radioctiva

Ficha tecnica:

Radiancia: 5.9 Kilopluts a temp. ambiente
Queso: 1.8 Kilogramos
Tomate: 4.5 Terawatts

Aceitunotones nominal: 2 (ya disipados)
Vida Media: 9 minutos desde la salida del horno

miércoles, 24 de marzo de 2010

Como escribir una extension ruby en C en 5 minutos

Lo siguiente toma lugar entre las 15:51 pm y las 15:56 pm

Para crear una extension en ruby lo primero que hay que hacer, es crear el "extconf.rb", basicamente tiene que tener el siguiente contenido:


# extconf.rb
require 'mkmf'

dir_config("exttest")

create_makefile("exttest")


Posteriormente, hay que crear el archivo del codigo fuente en C de la extension, que minimamente tiene que haber uno, en este caso creamos uno de prueba, bastante resumido, el cual crea un modulo ruby y le define dos metodos, ambos implementados en C:


// exttest.c

#include "ruby.h"

static VALUE foo(VALUE self) {
printf("Foo invoqued\n");
return Qnil;
}

static VALUE sum(VALUE self, VALUE a, VALUE b) {
return INT2NUM( NUM2INT(a) + NUM2INT(b) );
}


void
Init_exttest()
{
VALUE rb_exttest = rb_define_module("Exttest"); // definir el modulo

rb_define_singleton_method(rb_exttest, // en que modulo
"foo", // nombre del metodo
foo, // puntero a la implementacion C del metodo
0 // cantidad de argumentos del metodo
);

rb_define_singleton_method(rb_exttest, // en que modulo
"sum", // nombre del metodo
sum, // puntero a la implementacion C del metodo
2 // cantidad de argumentos del metodo
);

}




Para generar el makefile (solo hay que hacer esto una vez), se ejecuta el script extconf.rb:

ruby extconf.rb


Para construir la extension, se debe lanzar el siguiente comando:


make


Eso genera, entre otros archivos intermedios, extconf.so, el cual contiene la extension misma compilada a codigo nativo de la plataforma donde estan corriendo todo, para instalarla en el sistema, hay que correr (como root):


make install


Para usar la extension:



# test.rb
require 'rubygems'
require 'exttest'

Exttest.foo # el metodo foo definido en exttest.c!!
print Exttest.sum(4,9),"\n" # el metodo sum definido en exttest.c!!



Posteriormente, se pueden hacer cosas mas interesantes como definir clases, clases anidadas en modulos, metodos, etc...
Para la proxima voy a explicar como encapsular la extension como gem y distribuirla

links:

* http://onlamp.com/pub/a/onlamp/2004/11/18/extending_ruby.html: Fuente que inspiro este articulo y ejemplo practico de como wrappear la libreria GenX como libreria ruby GenX4r
* http://rhg.rubyforge.org/chapter04.html: Tutorial que muestra como definir clases y modulos
* http://ruby-doc.org/doxygen/1.8.4/group__ruby__interp.html: Documentacion completa de funciones C para definir extensiones de ruby incluyendo funciones de conversion de datos

miércoles, 10 de marzo de 2010

En github solo se tarda 60 SEGUNDOS

Esta mañana, entre a la internet con la idea de migrar un proyecto que tenia en googlecode (con svn) a git (y el mas conocido repositorio gratuito en internet de git es github)
El hecho de tener que migrar commits de svn a git ademas de la registracion, setup del repo git y demas cosas me hacian imaginar q seria una experiencia de trabajo.
Pero me soprendi: no solo registrarse y crear el repositorio fueron tres simples clicks, sino que tambien hay literalmente un boton "migrar SVN a GIT" en el cual solo te pedia la url del servidor svn... tras la operatoria (que encima fue rapida), pude ver mis commits convertidos a git.
Asi que el que este entusiasmado con git, sabe que no solo puede registrarse facilmente a un repositorio git gratuito sino que puede tambien migrar cualquier repositorio de svn para no perder la valiosa informacion de los commits en la mudanza.

Enlaces:

GitHub:
http://github.com/

GoogleCode ( Aun asi esta bueno si quieren usar un repo svn y el issue-tracker les puede gustar :) ):
http://code.google.com/

miércoles, 24 de febrero de 2010

Analisis de mergeo en git

Cada vez que se mergea una rama en otra, es necesario conocer que modificaciones se estarian introduciendo concretamente en la rama de destino antes de proceder al mergeo mismo.

El comando git-merge-base permite saber cual es el "common parent" de dos commits dados, es el "merge-base" el que define que segemento de cambios se incluiran al hacer el mergeo.

Supongamos que se quiere mergear a la rama xxxxx, los cambios de la rama yyyyy, pero antes se desea conocer que cambios se incluiran


# se cambia la rama de trabajo a yyyyy
$ git checkout yyyyy

# se busca el "merge base
$ git merge-base HEAD xxxxx
123456789abcdef

# se analizan los cambios que se incluiran viendo el segemento de cambios desde el merge-base
# hasta el ultimo commit de xxxxx
$ git log 123456789abcdef..xxxxx
( aparece una enumeracion de los commits que se van a incluir si se procede al mergeo)

# o tambien, se podria
$ git log $(git merge-base HEAD xxxxx)..xxxxx
( aparece la misma salida que del comando anterior)

# si se aceptan los commits vistos en el log, se procede al mergeo
git merge xxxxx


NOTA: Ademas de usar estos practicos comandos ayuda bastante mantener una nomeclatura y una gestion ordenada de las ramas que permitan tener en claro cuales son los "merge-base" de los mergeo que se ejecutaran.