Mañana arranca Fábrica de fallas

Este fin de semana (15 Y 16 de noviembre) de 14 A 21 Hs arranca el festival «Fábrica de fallas» que propone entrecruzar ideas y experiencias vinculadas a la cultura libre y el copyleft.

El evento se realiza en LA TRIBU – LAMBARÉ 873 Buenos Aires con entrada libre y grauita. Acá hay una transcipción del mail que vi circulando.

Una lástima tener que perdermela por no estar en la ciudad :(, pero hay varias actividades interesantes para los que deseen ir.

GMail agrega Videochat

Hoy me reenviaron una noticia que decía que GMail agregaba Videochat en su interfaz web, así que en la oficina nos pusimos a jugar. Lo primero que tuve que hacer yo es ir a esta página e instalarme un paquetito para tener soporte, ya que en OSX por default no me lo tomaba.

En Windows esto lo instala en background previa confirmación. Todavía no encontré qué es exactamente lo que hace (codecs tal vez?) ya que al usar la webcam y mic desde Flash no debería hacerle falta mucho. Lamentablemente no hay soporte para Linux, ya que Adobe es incapaz de darnos soporte de V4L en Flash (de hecho es incapaz de darnos un player decente :P).

En las pruebas cortitas que hicimos tanto el audio como el video es realmente bueno, casi al nivel de Skype (este último tiene un poco mejor de resolución en el video). Esperemos que soporten en GTalk pronto y que la implementación sea transportable a otros clientes Jabber, a ver si finalmente tenemos una opción decente para videochat libre.

Mono Internal Calls

Para mi tesis una de las cosas que tenía que lograr era pasar datos desde una aplicación escrita en C# (en realidad en cualquier lenguaje soportado) y el JIT. No quiero entrar en mucho detalle del por qué tengo que hacerlo ni cómo (porque la verdad esto último todavía no lo tengo resuelto :P).

Empezando a investigar caí en Embedding Mono, un articulo donde explican cómo embeber Mono en tu aplicación, por ejemplo para permitir plugins en .NET. El artículo tiene poco que ver con lo que yo estoy haciendo, pero me orientó en mi tarea.

Con Mono tenemos dos formas de ejecutar código nativo : P/Invoke e Internall Calls. El primer método es bastante usado para hacer wrappers de bibliotecas por lo simple que resulta usarlo, además de agregar algunos chequeos en la conversión de datos entre ambos mundos. El segundo es más bien el que me interesa a mi, ya que da un control más de bajo nivel y tiene menos overhead.

La forma de declarar en una clase de C# que un método está implementado en C es declarar un método externo y aplicarle un Attribute para marcarlo como Internal Call. No encontré que otro tipo de métodos externos existe, por lo que no entiendo bien por qué hay que poner ambas cosas :

using System;
using System.Runtime.CompilerServices;
	
class Hello {
  [MethodImplAttribute(MethodImplOptions.InternalCall)]
  extern static string Sample ();
}

Y por otro lado debemos decirle a la VM qué método nativo es el que se debe ejecutar :

/* Somewhere in a C program */
mono_add_internal_call ("Hello::Sample", sample);

Con eso en general basta y funciona. Pero … siempre hay un pero :). Preguntando por IRC me comentaron que esto está pensando, justamente, para los que quieren embeber el runtime de Mono en su aplicación, y no para extender la VM. En mi caso que necesito extender la Common Object Runtime Library (corlib.dll) y la forma «correcta» sería entonces como sigue a continuación.

Declarar una Internal Call (ICALL) que exista desde el inicio no fue tan tan trivial como parecía. Para empezar tuve que navegar entre muchos macros y un código en C poco documentado :).

Finalmente entendí lo que debía hacer y el resultado fue agregar el siguiente código en el archivo icall-def.h :

/* mono/metadata/icall-def.h */
/* Debe estar ordenado alfabeticamente */
ICALL_TYPE(MESSAGE, "System.Message.Message", MESSAGE_1)
ICALL(MESSAGE_1, "DefinePattern", icall_System_Message_DefinePattern)

Al principio lo definí al final de todo, para mantener separado mi código del de Mono, pero cuando ejecuté por primera vez mi ejemplo se quejaba que «System.Message.Message» debía estar después de «System.Buffer». Investigando un poco encontré que hacen una búsqueda binaria para los métodos internos que son parte de la VM y por eso el requerimiento de estar ordenado.

Al parecer la diferencia con el primer método es que usa un vector estático (que se crea con los macros) y cuando llamamos a mono_add_internal_call usa una GHashTable. La ventaja del array estático es que todo se resuelve en tiempo de compilación, cuando con el hash es todo en runtime.

El macro ICALL_TYPE nos permite empezar a definir un tipo que va a tener una ICALL, teniendo que especificar en el segundo parámetro el nombre completo (es decir, con el namespace) de la clase. El tercer parámetro es el nombre de la primer definición de los métodos que tiene esta clase.

Con ICALL luego definimos para cada método, que función debe ejecutarse en C, siendo en este caso :

void icall_System_Message_DefinePattern(MonoAppDomain *ad, MonoString *pattern)
{
  char *str = mono_string_to_utf8 (pattern);
  g_print ("New pattern Defined : %sn", str);
}

Para poder usar esto desde C# agregué un namespace a System, algo muy tonto y simple a puros efectos de ver si andaba. Para eso agregué el archivo mcs/class/System/System.Message/Message.cs con el siguiente código :

#if NET_2_0
using System;
using System.Runtime.CompilerServices;

namespace System.Message
{
  public class Message
  {
    public Message (string p)
    {
      DefinePattern (p);
    }
	
    [MethodImplAttribute (MethodImplOptions.InternalCall)]
    internal extern void DefinePattern (string pattern);
  }
}
#endif

Me queda todavía la duda de la diferencia exacta de éste método y el explicado en el artículo, ya que yo estoy declarando mi método como «internal extern» y no solamente «extern». El «internal» salió por prueba y error mirando métodos de otras clases y ya veré de preguntar cuál es la diferencia exacta entre ambos casos.

Una vez compilada e instalada la nueva VM y compilado el siguiente ejemplo :

using System.Message;
public class Test
{
  static public void Main(string [] args)
  {
    Message m = new Message("void Test* (*)");
    System.Console.WriteLine("Test Done");
  }
}

Obtuve lo esperado y «solo» tuve que pelear 6hs 😀

gazer@Dana:~/src/ejemplos$ mono Test2.exe 
New pattern Defined : void Test* (*)
Test Done

CSS Tab menú

Trabajando en un sitio me topé con el problema de tener que implementar tabs para el menú de navegación a fin de seguir el boceto que había pasado el diseñador.

El principal problema era que el tab tenía que ser auto-expandible ya que no sabemos de entrada qué textos van a ir en cada tab. Lo segundo que tenía que soportar es dos estados para los tabs, para poder saber cuál es el que corresponde a la página actual.

La solución final no es del todo ideal, ya que el texto de cada tab no puede ser arbitrariamente largo, pero en nuestro caso es por ahora lo suficiente y llegado al caso se puede extender fácilmente. Luego de trabajar un buen rato logré lo que sigue :

El HTML que genera el menú incluye tanto los tabs con sus respectivos links, como la fina línea negra y naranja de abajo (que hace de cierre), quedando algo cómo :


Cada tab está formado por dos imágenes aplicadas mediante CSS de manera de lograr el efecto deseado. El span interior al anchor es necesario para hacer que sea de largo variable. No me gusta mucho usar tags como helpers de los CSS, pero muchas veces no queda opción. Las imágenes en cuestión son :

El largo de la primera imagen es lo que define el largo máximo del tab que podemos tener. Para nuestro sitio consideramos que 250px de largo era más que suficiente.

Yendo a los CSS, a continuación está el CSS que se aplica a la lista, definiendo la línea separadora como un background alineado al fondo y que repite horizontalmente.

ul#navigation {
  list-style: none;
  padding: 0 0 0 9px;
  margin: 0 0 0 0;
  background: transparent url(images/menu_separator.png) repeat-x scroll left bottom;
  height: 49px;
}

El truco para poder hacerlo extensible es usar el tag span para poner el cuerpo (imagen 1) y luego usar el a para cerrar el borde de la derecha (imagen 2)

ul#navigation li a {
  background: transparent url(images/menu_2_off.png) no-repeat scroll right top;
  height: 36px;
  float: left;
  padding-right: 15px;
  margin-left: 3px;
  text-decoration :none;
  color: #000;
  text-align: center;
}

ul#navigation li a span {
  background: transparent url(images/menu_1_off.png) no-repeat scroll 0 0;
  display:block;
  height: 36px;
  padding: 0.7em 0 0 1em;
}

Los tamaños, margenes y paddings son en función del tamaño de las imágenes. Para el caso del tab seleccionado solo basta cambiar los background y ajustar algún que otro color :

ul#navigation li.current a {
  background: transparent url(images/menu_2_on.png) no-repeat scroll right top;
}

ul#navigation li.current a span {
  background: transparent url(images/menu_1_on.png) no-repeat scroll 0 0;
  color: #fff;
  font-weight: bold;
}

Para que ande en IE hay que aplicar algunos hacks específicos para que no se rompa todo, pueden hacerlo usando los include condicionales :

/* IE hacks */
ul#navigation {
  /* El ancho de la barra de navegación */
  width: 1004px;
}

ul#navigation li {
  display: inline;
}

ul#navigation li a span {
  display: inline;
}

Academia Wikipedia

En el día de ayer estuve en la «Academia Wikipedia«, un evento realizado por Wikimedia Argentina, representante en Argentina de la Wikimedia , organización detrás del Wikipedia y muchos otros proyectos.

Hubo varias charlas introductoria a los conceptos y filosofías básicas que rigen en el proyecto, los pilares en los que se apoya, y cómo comenzar a formar parte y dejar de ser un lector pasivo, etc. También se desarrollaron talleres de edición wiki, para aquellos que nunca habían usado un wiki y entender como dar formato, como hacer referencias a otros documentos, como usar el historial, discutir los artículos, etc.

La charla de cierre fue dada por Jimmy Wales, fundador del proyecto, en una exposición muy amigable sobre Wikipedia y otros proyectos anexos como pueden ser Wikisource o Wikicommons.

De su charla rescato dos momentos realmente interesantes. El primero acerca del Muppet Wiki y sus 17,823 artículos. El segundo tratando de explicar el por qué de las políticas de permiso de Wikipedia haciendo una analogía con un restaurante, no creo que transcribirla sea igual de gracioso o entendible, así que no lo voy a hacer :).

Ya entrando la noche, la sed y el hambre, nos fuimos a comer pizza y tomar cerveza para terminar la jornada.

[rec]

Hoy me decidí a alquilar [rec], una película española que toma varias ideas de otras película. Imagínense un The Blair Witch Project (mejor filmada) mezclado con un 28 Days Later, un poco de Cloverfield y una galleguita de ojos claros :).

La película está muy buena, por momentos me hizo pegar unos saltos (maldito 5.1 :D). La historia no es la gran cosa, pero este tipo de películas suele ser así. Mucha gente encerrada por alguna razón extraña, ruidos raros, gente que empieza a morir para luego revivir para luego volver a morir.

Publicado en DVD

Delegando atributos de ActiveRecord

El otro día tratando de mejorar un modelo de una aplicación me topé con el problema de tener muchos atributos virtuales para poder acceder a atributos de un objeto relacionado y no caer en lo siguiente :

class Player < ActiveRecord::Base
  belongs_to :user

  def name
    user.name
  end

  def email
    user.email
  end

  # ... y varios más
end

Esto no lo puedo evitar mucho ya que Player es una clase intermedia en una relación de N-M entre los usuarios y los partidos, y además contiene información necesaria para la lógica del modelo.

Tampoco era muy feliz tener por todos lados Message Chains:

@player.user.name
@player.user.email
# etc ....

Una de las recomendaciones que se usan en estos casos es Hide Delegate para ocultarle al cliente de donde sale el dato realmente. Cabe aclarar que no siempre son un problema las llamadas encadenadas.

Recordando el anuncio de Rails 2.2 noté que al final hablaba de un delegate que tenía un nuevo feature. Buscando un rato por google encontré este post donde hablaba de un método delegate para hacer justamente esto que yo quería.

Lo extraño, que también menciona el autor es que no está documentado en la API oficial de Rails aunque mirando el código veo que explica como usarla. Explícitamente dice :

Provides a delegate class method to easily expose contained objects’ methods as your own

En la documentación también aclara que es útil tanto para atributos propios como para asociaciones entre diferentes instancias de ActiveRecord. La realidad es que por cómo está implementada funciona para cualquier objeto ruby que se nos ocurra.

El ejemplo con el que empezamos el post quedaría resumido a :

class Player  :user
end

Quedando mucho más corto el código, por lo tanto más fácil de mantener.

Tomando prestado los ejemplos del otro blog, también podemos hacer cosas con atributos que no son asociaciones, como por ejemplo una fecha :

# Forma abreviada
class Content  :published_at
end

# Forma desglosada
class Content  :published_at
  delegate :month, :to => :published_at
  delegate :day, :to => :published_at
end

# Podemos escribir
@content.year

# en lugar de
@content.published_at.year

Refactoring de «Fat Methods» – Episodio 3

En el Episodio 1 trabajé el método Matches#create y había dejado una parte a la que Des preguntó por qué la ignoraba. En ese momento no quería extender mucho más el post por lo que en esta oportunidad vamos a completar el refactoring pendiente.

El código que habíamos logrado en ese momento es el siguiente:

  def create
    @match = current_user.matches.create!(params[:match])

    @notifications = @match.owner.friends.select {|f| f.notify_new_matches? }.collect(&email)
    Emailer.deliver_match_created(@match, @notifications) if @notifications.any?

    flash[:success] = "El partido fue creado."
    redirect_to matches_path
  rescue
    render :action => 'new'
  end

Lo que nos quedaba terminar era cómo mejorar el envío de las notificaciones para aquellos amigos que tenían activa dicha opción. Como primer paso vamos a separar la lógica del mailer de manera que no quede mezclado en el controller, y ya que estamos, que no importa donde se cree un partido el email salga igual sin la necesidad de copiar y pegar código.

Una opción es usar un callback after_create como ya hicimos en el post pasado, pero a mi no me gusta mezclar en los modelos lógica que no tiene que ver con la persistencia. La razón es que esta tarea de enviar emails no es algo propio de un modelo, no debería tener esa responsabilidad. Pero dejarla en el controller sería «irresponsable» :P.

Una opción, no muy acertada, podría ser usa un filtro que se ejecute después del create (after_filter) pero quizás no siempre tendríamos la posibilidad de ejecutar un filtro. La mejor opción es utilizar un Observer para mirar al modelo Match, y cuando uno nuevo es creado, ejecutar nuestro código.

Los Observers se registran a si mismos a un modelo dado escuchando los callbacks que nosotros definamos. Estos callbacks son los mismos que existen en ActiveRecord, siendo algunos : after_create, before_create, after_save, etc…

Como vemos, el Observer es casi lo mismo (a nivel práctico claro está) que usar los callbacks de ActiveRecord pero sin tener que mezclar acciones que no son propias de los modelos. Muchas veces uno se olvida que existen ya que generalmente se los utiliza para las estrategias de invalidación de cache (que puntualmente estos observers se llaman Sweepers).

El código del observer quedaría ahora :

  # app/model/match_observer.rb
  class MatchObserver < ActiveRecord::Observer
    def after_create(contact)
      @notifications = @match.owner.friends.select {|f| f.notify_new_matches? }.collect(&:email)
      Emailer.deliver_match_created(@match, @notifications) if @notifications.any?
    end
 end

Como se ve, en ningún lugar hacemos referencia al modelo observado. Esto es porque Rails lo infiere automáticamente a partir del nombre del Observer. Claro está que si por alguna razón usamos un nombre que no permita inferirlo lo podemos especificar.

Lo único que faltaría es decirle a Rails que existe el Observer, para que lo cargue y lo registre con la clase correspondiente. Para eso debemos agregar en nuestros environment lo siguiente :

  config.active_record.observers = :match_observer

Ahora si, veamos como quedó nuestro controlador totalmente refactorizado :

  # Dentro de matches_controllers.rb
  def create
    @match = current_user.matches.create!(params[:match])
    flash[:success] = "El partido fue creado."

    redirect_to matches_path
  rescue
    render :action => 'new'
  end

Ahora si nuestro controlador está bastante mejor. Para la próxima entrega vamos a como mejorar las asociaciones de los modelos para poder cambiar el match.owner.friends.select que no es para nada prolijo.

Lo que viene en Rails 2.2

Hace poco se anunció el RC1 de lo que será la versión 2.2 de Ruby on Rails. Si bien la fecha de salida es «cuando esté lista», ya se pueden utilizar para aquellos que gusten vivir «on the edge».

Para aquellos que quieran un rejunte completo de todo lo que se viene pueden ver el post : What’s New in Edge Rails: Rails 2.2 Released – Summary of Feature.

Yo acá voy a comentar solo lo que tuve la oportunidad de probar y que me resultó útil.

I18n

La verdad es que es una buena noticia, no para mi porque hago todo para un solo idioma :P, pero algún día puede resultar útil. Lo único que a mi me deja con sabor a poco es la forma en que se hace que no me termina de gustar. Antes que nada quiero aclarar, porque ya vi la pregunta en un par de listas de correo, que esto localiza textos, no el contenido de una instancia de ActiveRecord. Si uno quiere que el contenido que cargan los usuarios sea traducido, es otra historia :).

Las traducciones se escriben en ruby o en archivos YAML, con «hashes» que pueden estar anidados (como si fueran «namespaces«) :

# lib/locale/en-US.rb
{ 'en-US' => {
  :hello_world => "Hello World",
  :hello_flash => "Hello Flash"
}}
 
# lib/locale/pirate.rb
{ 'pirate' => {
  :hello_world => "Ahoy World",
  :hello_flash => "Ahoy Flash"
}}
 

Y luego en las vistas (o mailers o donde sea) en lugar de poner el texto se ingresa el symbol asociado al texto que cargamos en las traducciones, por ejemplo :

Mi problema particular con este método es que estoy mucho más acostumbrado a cómo se hace con gettext (que no necesariamente es la mejor forma) donde se ponen todos los textos en inglés en la aplicación y después se escriben las traducciones.

Hay un demo online acá, que en estos momentos está caído, espero que para cuando lean esto ya este funcionando de nuevo.

Join Tables Conditions

Esto es algo que realmente hacía falta. Vamos a ver la mejora con un ejemplo. Supongamos que tenemos los siguientes modelos :

class Article < ActiveRecord::Base
  belongs_to :user
end

class User < ActiveRecord::Base
  has_many :articles
end

y queremos obtener todos los usuarios que tengan al menos un artículo publicado. Para eso deberíamos hacer :

User.find(:all, :joins => :article,  :conditions => ["articles.published = ?", true])

Con la nueva sintaxis es posible especificar este tipo de queries de una manera más amena como sigue :

User.find(:all, :joins => :article, :conditions => { :articles => { :published => true } })

ActionMailer Layouts

Algo que si me tocó vivir es tener varios emails HTML con un mismo formato y que cambiaba el contenido (Tu amigo te invitó, Tu nueva clave es, Ganaste un premio, etc). Con el mailer actual casi que hay que hacer un copy & paste del marco y despuer cambiar para cada tipo de email la lógica de qué se muestra.

En rails 2.2 ahora vamos a tener layouts como los tenemos en ActionView, de manera de tenerlo una vez y si arreglamos o cambiamos algo cambia para todos.

Memoization

Es muy frecuente que uno agregue lógica simple de caching en los modelos para las variables de instancia como se ve en el siguiente ejemplo :

  class User < ActiveRecord::Base
    def full_name
      @full_name ||= "#{first_name} #{last_name}"
    end
  end

Esto lo hacemos para evitar el overhead de crear el full_name si lo llegamos a usar varias veces en una misma vista, de manera que el string se crea en la primer llamada y en las siguientes solamente lo retorna.

Los puristas dicen que en realidad está mal, porque se está responsabilizando al método de algo que en realidad no debería importarle : la política de caching. ¿Suena exagerado? Seguramente :).

Para solucionar esto se agregó el método memoize que nos permite a agregar a un método común este tipo de lógica de manera separada :

  class User < ActiveRecord::Base
    def full_name
      "#{first_name} #{last_name}"
    end

    memoize :full_name
  end

Esto se encarga de que cuando llamemos a @user.full_name se comporte de la misma manera que el primer ejemplo, sin tener que modificar el método. También nos permite saltarnos el «cache», por ejemplo si en la lógica acabamos de cambiar el nombre de pila, debemos forzar para que el nombre completo cambie :

   @user = User.new :first_name => 'Test', :last_name => 'Test'
   @user.full_name # => Test Test
   @user.first_name = 'Do'
   @user.full_name # => Test Test
   @user.full_name(true) # => Do Test

Y más

Hay varios cambios más, como Thread Safety, ETag, partial GETs y demás que a mi por ahora no me interesan y por eso no me entiendo mucho más. Pueden consultar el anuncio oficial para ver de que se tratan o cómo pueden hacerle la vida más fácil :).