format internet:

…por favor espere (34% finalizado)…

Archivos para 'ruby' Categoría


masochism: plugin para replicación master-slave en MySQL

Publicado por javier ramirez en Mayo 18, 2008

Recientemente me he encontrado con la necesidad de trabajar desde Rails contra una base de datos MySQL replicando en modo master-slave.

Replicación Master-Slave In a Nutshell:

La idea de montar un master-slave es tener la base de datos maestra para realizar las modificaciones a la base de datos, y usar la/las bases de datos esclavas para realizar las lecturas. De esta forma, las operaciones de lectura, que son las más habituales, se pueden balancear entre diferentes instancias de una base de datos.

Por otro lado, cada vez que se hace una modificación en la maestra, esta modificación se replica en las esclavas, de forma que los datos siempre están sincronizados.

Esta imagen del manual online de MySQL es muy explicativa

mysql master slave

Claramente este esquema nos puede ayudar mucho de cara a la escalabilidad de una aplicación, ya que la base de datos es uno de los cuellos de botella típicos.

Lo que necesitamos en este caso, es asegurarnos de que todas las operaciones de escritura van contra la conexión de la maestra, mientras que las lecturas van por una conexión esclava.

Una de las ventajas de usar un framework- en este caso Rails, pero podría haber sido cualquier otro- es que tu aplicación tiene una arquitectura bien definida. O al menos debería. Esto significa que al usar Rails tenemos bajo control las operaciones que se hacen contra la base de datos, con lo que identificar las de lectura y las de escritura debería ser simple. Si seguimos las reglas del framework, las operaciones contra la base de datos pasarán siempre por el modelo y por los métodos que AR nos proporciona.

Al final, el número de métodos que realmente acaban accediendo a la base de datos son más bien pocos, con lo que podríamos jugar un poco con el framework, establecer dos conexiones con la base de datos (una con la maestra, y otra con la esclava) y decidir qué conexión va a usar cada método. Así todos los métodos “find” y similares irían por la esclava, y los “delete”, “insert”, etc.. irían por la maestra.

Esto mismo es lo que el plugin masochism hace automáticamente por nosotros. El plugin viene de la mano del hiperproductivo Rick Olson.

Uno de estos días tendré que contar en más detalle cómo va, pero el resumen ejecutivo es que lo instalas, le añades una conexión master_connection en tu fichero database.yml, llamas a un método en uno de tus initializers… y te olvidas. A partir de ahí todo funciona de forma transparente (siempre que hayas configurado tu master/slave de MySQL previamente, claro).

De momento le he encontrado una única pega. Entre los métodos que se envían a la base de datos maestra no está el método “execute”, que es el típico método que sólo utilizas cuando quieres modificar algo en la base de datos. Sin ir más lejos, el (imprescindible) plugin Foreign Key Migrations usa ese método para crear las FK, por lo que si no nos aseguramos de que se usa la base de datos maestra, podemos tener problemas.

Le he mandado un parche (en realidad es añadir una palabra y una coma) a Rick , a ver si le parece apropiado incuírlo como parte del plugin.

update: y el patch ya ha sido incluído :)

Y a escalar!!

searchwords: scalability, mysql replication, master-slave, javier ramírez

Publicado en desarrollo, javier ramirez, ruby, ruby on rails, ruby on rails | Etiquetado: , , , , | 3 Comentarios »

madrid-rb el grupo de ruby (y ruby on rails) de madrid

Publicado por javier ramirez en Abril 22, 2008

Después de unos meses de silencio por overflow de actividades extraescolares, voy a intentar retomar el blog… aunque veremos lo que dura porque dentro de un par de días empiezo a dar clases otra vez.

Aprovecho la ocasión para anunciar la creación de madrid-rb, el grupo de ruby de madrid. Queremos organizarnos un poco y retomar las quedadas que se hacían hace tiempo, pero dándoles un carácter mensual. En concreto el último jueves de cada mes.

La idea es vernos, hacer comunidad, buscar puntos de encuentro comunes, dar alguna charlita ligera, juntarnos para hackear un poco y quizás crear alguna gema o algún plugin… y usarlo como excusa para salir un jueves al mes :p

La primera cita es este mismo jueves, a las 19:30, en el Starbucks de la calle Génova 4 en madrid.

El grupo se está organizando a través de este grupo de google. Además también tenemos un grupo creado en working with rails.

Y, lo anunciaré en la quedada del jueves, pero lo voy dejando ya por aquí, me han aprobado un proyecto en rubyforge para que podamos dejar el código que vayamos haciendo. Como puedes subir tus páginas estáticas y rubyforge mola, llevo idea de proponerlo para subir la home del grupo ahí.

Si no quieres perderte ninguna cita, hay disponible un calendario al que te puedes suscribir.

searchwords: madridrb, madrid, quedada, rubyforge, google groups

Publicado en conferencias, desarrollo, internet, javier ramirez, madrid, madridrb, ruby, ruby on rails | 1 Comentario »

splat operator

Publicado por javier ramirez en Noviembre 4, 2007

Cuando crees que ya sabes Ruby, de repente te encuentras con algo que no conocías. A mí me pasó hace unas semanas con el splat operator (lo que David A. Black llama “the unary unarray operator” o “el operador unario de desarraymiento” :p )

El splat operator, que se representa con el asterisco en ruby, lo había visto para pasar un número variable de argumentos en definiciones de métodos, por ejemplo en el find de ActiveRecord, pero nunca me había planteado qué es lo que hacía exactamente.

Pues bien, básicamente lo que hace el splat operator es o bien separar un array en diferentes objetos, o bien agrupar diferentes objetos en un array, dependiendo si lo usamos a la derecha o a la izquierda de una expresión ruby.

Por ejemplo, en ruby podemos utilizar una expresión tal que


variable1,variable2=['valor1','valor2','valor3']

En ese caso, la variable1 acaba valiendo ‘valor1′ y la variable dos acaba valiendo ‘valor2′. El valor ‘valor3′ se pierde.

Usando el splat operator, podemos escribir esta expresión


variable1,*variable2=['valor1','valor2','valor3']

En este caso, la variable2 acabará siendo un array que contiene dos elementos ['valor2','valor3']. Éste es precisamente el uso que se hace cuando se define un argumento de una función con el splat operator. Todos los objetos que se pasen en la invocación al método a partir de ese argumento, se recibirán directamente como un array.

Si intentamos hacer algo como


variable1,*variable2,variable3=['valor1','valor2','valor3']

Obtendremos un error. El asterisco indica que se va tomar todo lo que venga a partir de esa posición para componer un array. Por este motivo, no podemos tener una variable para asignarse después, ya que no quedaría nada en el lado derecho de la expresión para ser asignado. Por este motivo, cuando usamos un número variable de argumentos solamente podemos aplicarlo en el último argumento de nuestro método.

Creo recordar que en una entrevista a Matz que lei una vez, hablaba de que una de las mejoras en Ruby 2 sería la posibilidad de definir argumentos variables al principio o al final de la cadena de argumentos, así que puede que el comportamiento del splat operator cambie para entonces, si finalmente se implementa esa funcionalidad.

Hasta aquí hemos visto cómo se comporta el splat cuando se usa en el lado izquierdo de una expresión, es decir, cuando lo usamos para convertir diferentes objetos en un array. Pero el splat tiene aplicaciones muy interesantes cuando se usa en el lado derecho de una expresión, es decir, cuando se usa para separar un array en diferentes objetos.

Uno de los casos interesantes es el uso en un when para ver si un valor está incluído en un array. Copio aquí un ejemplo directamente del antiguo blog de why


BOARD_MEMBERS = ['Jan', 'Julie', 'Archie', 'Stewick']
HISTORIANS = ['Braith', 'Dewey', 'Eduardo']

 case name
 when *BOARD_MEMBERS
   "You're on the board!  A congratulations is in order."
 when *HISTORIANS
   "You are busy chronicling every deft play."
 end

Francamente interesante. En lugar de hacer un include?, directamente el splat expande el array in situ a sus valores, de forma que a todos los efectos es como si estuviera escribiendo inline el contenido del array separado por comas. Rizando el rizo, esto me permite hacer un case tal que


when 'admin'|*HISTORIANS|*BOARD_MEMBERS

Y por último, una de mis aplicaciones favoritas del splat operator: guardar en un array los argumentos para la llamada a una función que espera un número fijo de argumentos, y usar el splat para convertir el array en los argumentos individuales en el momento de la llamada.

Un ejemplo de la vida real. Tengo un método definido con la siguiente signatura


def Red.upload_indexes(producto_id, max_per_batch=REDCFG::MAX_PER_BATCH, output_file=nil )

Como se puede ver, este método puedo invocarlo con uno, dos o tres argumentos. Ahora quiero escribir un script que me permita lanzar este método desde la línea de comando mediante script/runner. Una opción sería modificar mi método para que reciba siempre un array y que en función de cuántos argumentos lleguen discrimine. Sería una solución, pero mi signatura pierde expresividad, y eso no me gusta.

¿Qué tal si hago lo siguiente?


ruby script/runner "Red.upload_indexes(*$ARGV[1..-1])" %1 %2 %3 

¡¡¡Funciona!!! ¿Qué estamos haciendo exactamente? Estoy recogiendo el array de parámetros de entrada ARGV, y me quedo con todos los parámetros excepto el primero, que es el nombre del script. Ahora al array de argumentos le aplico el splat operator, con lo que se expande en sus variables individuales. Si me llaman con un argumento, se invocará a mi método con un sólo argumento, si se pasan dos o tres, se invocará correctamente.

Este mismo uso lo puedo aplicar con técnicas de metaprogramación, por ejemplo si estoy componiendo llamadas a métodos sobre la marcha y usando send.


mi_objeto.send('nombre_de_metodo',*array_con_los_argumentos)

Y ya por último, otro ejemplo más de la vida misma. En esta ocasión extendí la clase Array para que me de todos los elementos de un array excepto los que estén en las posiciones que a mí me interese. Es el inverso a values_at


class Array
  def select_except(*indexes)
    self.values_at(*(Array.new(self.size).fill{|i| i} - indexes))
  end
end

Aquí me defino un método que acepta un número variable de índices. Después, me creo un nuevo array con tantas posiciones como el actual, y que tiene como contenido los índices en sí mismos (0,1,2…). Ahora tomo este array y le aplico la operación de resta entre Arrays, con lo que obtengo como resultado un nuevo Array en el que están todos los índices que quiero extraer de mi array.

Ahora ya sé todos los índices que necesito extraer, y tengo un método values_at que me permite pasar una lista de índices y me devuelve el array correspondiente. El problema es que values_at no me admite un Array como argumento. No hay problema, aplicando el splat operator, consigo separar el Array en sus objetos miembro, con lo que todo funciona. Para clarificarlo, las siguientes dos líneas de código son equivalentes


[obj0,obj1,obj2,obj3].values_at(0,3)
[obj0,obj1,obj2,obj3].values_at(*[0,3])

Y con esto, que no es poco, se acabó lo que el splat operator da de sí.

searchwords: splat operator, variable number of arguments, metaprogramming, unary unarray operator

Publicado en desarrollo, javier ramirez, ruby, sin categoría | 2 Comentarios »

destructores en ruby

Publicado por javier ramirez en Septiembre 30, 2007

Viniendo de otros lenguajes de programación, cuando empecé con Ruby echaba de menos los métodos destructores de objetos. Igual que existe un método initialize, esperaba que hubiera un método finalize al que se invocase justo antes de que el garbage collector pasase a limpiar los objetos no usados.

Buscando un poco, di con la clase ObjectSpace, con la que se pueden hacer algunas cosas interesantes, como por ejemplo recorrer todos los objetos que existen en memoria en un momento determinado. Esta clase tiene un método, define_finalizer, que permite definir un hook que se llamará cuando el objeto se libere.

El problema es que, por como está implementado, cuando se invoca a este hook el objeto ya no puede existir en memoria, porque si existiese habría una referencia a ese objeto y entonces el garbage collector no lo limpiaría nunca. La verdad es que este comportamiento es bastante mejorable y, como bien dice aquí Charles Nutter, no es lo único mejorable de la clase ObjectSpace.

El caso es que ese comportamiento es el que hay, y con eso tenemos que jugar. Para el caso más sencillo, es tan simple como lo siguiente.


  a='cadena de prueba'
  ObjectSpace.define_finalizer(a,proc{|id| puts "finalizando el objeto #{id}"})
  a=nil
  GC.start

Si ejecutamos eso en la consola, podremos ver cómo, cuando pasamos el collector, se muestra la cadena indicando que se ha destruído.

Si lo que queremos es llamar a un método concreto, hay que tener en cuenta que el objeto ya se habrá destruído cuando se invoque su finalizador, así que podremos llamar solamente a métodos no asociados a la instancia. Lo normal en ese caso es llamar a métodos de la clase de este objeto. Por ejemplo


class TestClass
  def initialize
    ObjectSpace.define_finalizer(self,self.class.method(:terminate).to_proc)
  end

  def TestClass.terminate(object_id)
    puts "se ha destruÃ�­do el objeto {#object_id}"
  end
end

En el método terminate podríamos hacer lo que necesitásemos, siempre teniendo en cuenta que el objeto ya no existe. Si se tratase de liberar recursos abiertos a la hora de inicializarlo, que es el caso más común, se podría usar una Hash definida como variable de clase y guardar la referencia a los recursos que se abren usando el object_id como clave. De este modo, al llamar al método terminate, podríamos acceder con el id a esa Hash para poder liberar el recurso que nos interese.

En cualquier caso, hay que decir en defensa de Ruby que para muchos de los casos donde en otros lenguajes de programación usaríamos destructores de objetos, en Ruby usaremos bloques, quedando un código mucho más legible.

Por ejemplo


FantasticConnection.open(end_point) do |conn|
  conn.send(my_data)
end

searchwords: finalizer, finalize, destructor, constructor, garbage collector, colector de basura, ObjectSpace

Publicado en desarrollo, javier ramirez, ruby | Sin Comentarios »

usando method_missing y alias_method_chain

Publicado por javier ramirez en Septiembre 16, 2007

En este post voy a comentar cómo usar algunas de las características que más me gustan de Ruby y Rails: la posibilidad de reabrir una clase en cualquier momento, poder capturar las llamadas a métodos que no existen en un objeto, y la posibilidad de hacer alias de métodos (y encadenarlos)

Para ilustrar todo esto y ver qué podemos hacer, vamos a modificar el comportamiento de la clase Hash de forma que pueda hacer lo siguiente


>> me={:name=>’javier’}
=> {:name=>”javier”}
>> me.name
=> “javier”
>> me.last_name
NoMethodError: undefined method `last_name’ for {:name=>”javier”}:Hash
from (irb):18:in `method_missing’
from (irb):33
from :0

Si intento hacer eso sobre cualquier Hash, me devolvería un error directamente en la línea donde hago “me.name”, ya que la forma correcta de acceder a los elementos de una hash es mediante el operador []. La forma de acceder al campo “name” sobre una Hash cualquiera sería “me[:name]“. Con las modificaciones que vamos a realizar, conseguiremos un uso un poquito más conciso (a la manera que tiene ActiveRecord con los atributos de nuestro modelo).

Añadir el método ‘name’ a mi Hash sería muy simple. Aprovechándonos de que Ruby me permite reabrir una clase en cualquier momento, podría hacer simplemente esto


class Hash
  def name
    self[:name]
  end
end

Esto sería perfecto, pero implica que conocemos previamente el nombre de los campos a los que queremos acceder y además necesitamos escribir un método por campo. No parece una buena opción. Si conocemos previamente el nombre de los campos podríamos usar Struct y olvidarnos.

Entonces, si no sabemos previamente el nombre de los campos, ¿cómo sabemos qué métodos implementar? La respuesta es simple: no lo sabemos y no lo podemos saber. Pero… y ¿qué hacemos entonces?

Aquí es donde entra en juego una de las características que más me gustan de Ruby. Cuando un objeto recibe un mensaje que no entiende, Ruby automáticamente invoca a un método especial del Kernel. Este método es method_missing. Nota: ‘mensaje’ es el nombre que se usa en teoría de objetos cuando hablamos de un método. Realmente lo que tenemos son objetos que se envían mensajes entre ellos.

El método method_missing es un método del Kernel, pero si yo reabro una clase y defino el método, cuando se invoque a method_missing para esa clase conseguiré interceptar todas las llamadas a métodos no existentes. El intérprete de ruby nos va a pasar dos parámetros, el primero es el nombre del método, y el segundo son los parámetros que se usaban en la invocación, si los había.

Ahora ya podríamos hacer lo siguiente


class Hash
  def method_missing(method_name,*args)
    self[method_name]  if self.member?(method_name)
  end
end

Y esto ya casi hace lo que queremos, pero hay todavía un pequeño detalle. Si pedimos un campo que no existe, vamos a obtener un nil en lugar de una excepción. Esto no tiene porqué ser malo, y de hecho podría ser el comportamiento deseado. Pero no es lo que planteábamos originalmente. Queremos que si el campo existe nos lo devuelva, y si no existe se comporte como antes de sobreescribir el método.

Para poder hacer este tipo de cosas en Ruby, usamos la posibilidad de hacer alias de los métodos. La forma habitual es hacer un alias del método original con un nombre tal que loquesea_old y después desde el método nuevo que escribimos podemos invocar al antiguo mediante el alias definido. Esto tiene un problema inherente a la propia arquitectura de una aplicación en Ruby. Como las clases por definición se pueden reabrir en cualquier momento, cualquiera puede redefinir un método en cualquier momento, con lo que corremos el riesgo de estar ocultando un método sobreescrito previamente al hacer un alias.

Para evitar este tipo de problemas, en el código interno de rails se usa un patrón que funciona bastante bien. Cuando se define un nuevo método que va a ocultar a uno viejo al que se hará alias, se usa un sufijo para indicar qué tipo de funcionalidad implementa. Después se definen los alias de esta forma


alias :method_missing_without_access_by_key, :method_missing
alias :method_missing, :method_missing_with_access_by_key

A la hora de definir nuestro método nuevo, lo definiremos con el patrón nombre_antiguo_with_sufijo_indicando_funcionalidad. En nuestro caso se definiría como “method_missing_with_access_by_key”. De esta forma, aunque varios plug-ins diferentes intenten hacer alias de un mismo método, mientras no colisione el sufijo con uno que ya existe no tendremos problemas, con lo que se reduce el riesgo de tener conflictos de nombres.

Como este patrón es muy interesante, desde la versión 1.2 está implementado como parte del core de rails, bajo el nombre “alias_method_chain”. Podemos hacer simplemente


alias_method_chain :method_missing, :access_by_key

Esto busca un método que se llame method_missing_with_access_by_key y aplica los dos alias que hemos visto antes.

Así que la versión final de nuestro pequeño hack quedaría del siguiente modo


class Hash
  def method_missing_with_access_by_key(method_name,*args)
  self.member?(method_name) ? self[method_name] : method_missing_without_access_by_key(method_name,*args)
end

alias_method_chain :method_missing, :access_by_key
end

Todavía hay espacio para hacer alguna pequeña mejora, que probablemente explicaré en un post más adelante.

searchwords: method_missing, alias_method_chain, ruby alias method, Struct

Publicado en desarrollo, javier ramirez, ruby, ruby on rails | Sin Comentarios »

Seleccionar elementos de un Array de forma aleatoria

Publicado por javier ramirez en Septiembre 4, 2007

A veces viene bien poder mostrar el contenido de un Array de forma aleatoria en Ruby. Por ejemplo, puedes querer mostrar en una tagcloud los tags más populares pero no quieres mostrarlos en orden para que quede más estético.

Normalmente usamos el método sort_by en arrays compuestos de objetos complejos para compararlos por algún campo, por ejemplo para un resultado de una consulta de AR podríamos hacer:

my_array.sort_by{|x| x.amount}

Podemos utilizar el mismo método de una forma simple para “desordenar” cualquier Array:

my_array.sort_by{rand}

Y con esto tendremos un array desordenado “al azar”. Podríamos incluso abrir la clase Array y definir un método shuffle que hiciera justamente esto, tal que así

  class Array
    def shuffle
      self.sort_by{rand}
    end
  end

Y ahora ya podemos hacer:

my_array.shuffle

searchwords: ruby, array, sort_by, shuffle

Publicado en desarrollo, javier ramirez, ruby, ruby on rails | Sin Comentarios »