sábado, 10 de diciembre de 2011

Plantillas javascript

Las aplicaciones web que usan AJAX suelen seguir un patrón similar:
1) Se lanza un evento javascript
2) Se genera una petición al servidor
3) El servidor produce código javascript de vuelta con el objetivo de añadir/eliminar HTML de la página.

Cuando hay que insertar gran cantidad de HTML el código javascript producido suele ser poco mantenible, el primer planteamiento es crear una gran cadena de marcado HTML para insertarla en algún lugar de la página.

Por suerte, existe un plugin para la librería jQuery llamado jQuery Templates que elimina este problema.

Para usar este plugin, podemos definir una plantilla javascript de la siguiente forma:
<script id="templateId" type="text/x-jquery-tmpl">
${templateText}
</script>
Siguiendo este ejemplo, con el id 'templateId' recuperaremos posteriormente la plantilla y podremos hacer la sustitución de 'templateText' con la siguiente llamada.
$("#templateId").tmpl({templateText:"Hello world"})
Como se puede ver, es similar a cualquier sistema de plantillas, se puede interpolar marcado HTML, crear condicionales:
<script id="templateId" type="text/x-jquery-tmpl">
{{if error}}
<h2>Error!</h2>
{{else}}
<h1>OK</h1>
{{/if}}
</script>
$("#templateId").tmpl({error:false})
O incluso bucles:
<script id="templateId" type="text/x-jquery-tmpl">
<h1>${title}</h1>
{{each items}}
<li>${$value}</li>
{{/each}}
</script>
$("#templateId").tmpl({title:"Titulo", items:["uno", "dos", "tres"]})



domingo, 18 de septiembre de 2011

Batch processing en rails

En aplicaciones web con cierta complejidad, es común que aparte de responder a las peticiones de los clientes, se necesite realizar trabajos batch o simplemente migrar la base de datos a una nueva estructura.

Cuando la base de datos crece, aparecen nuevos problemas, uno de ellos es que las tablas de la base de datos pueden no caber en memoria. En hostings baratos este problema se acentúa ya que no se suele contar con demasiada RAM. Con ruby on rails es muy fácil solventar esta dificultad.

Tomando como ejemplo una tabla muy grande de usuarios en la que hay que recalcular un campo para cada usuario.
User.find_each{|u| u.karma = calculate_karma(:user => u)}
find_each toma bloques de 1000 usuarios y va devolviendo de uno en uno de forma transparente, se utilizan 1000 entradas por defecto pero se puede cambiar mediante el parámetro batch_size.
User.find_each(:batch_size => 200){|u| u.karma = calculate_karma(:user => u)}
find_each se implementa usando find_in_batches, se puede llegar a mayor nivel de control usando esta función que devuelve directamente los grupos de entradas.
User.find_in_batches(:batch_size => 2000){|group| group.each{|u| u.karma = calculate_karma(:user => u)}}
Puede que este último ejemplo parezca más complejo sin ningún tipo de beneficio, pero sería muy útil en caso de querer paralelizar el proceso.
User.find_in_batches(:batch_size => 2000){|group| Process.fork{calculate_karma(:group => group)}}

domingo, 4 de septiembre de 2011

Temporizadores en javascript: PollJS

Realizar tareas regulares en el tiempo en una web con javascript es una tarea algo pesada. PollJS es una librería muy pequeña y sencilla que facilita algo esta tarea.

Un ejemplo de una tarea regular con PollJS.
Poll.start({
    name: "refresh_list",
    interval: 1000,
    action: function(){}
});
Esa es la sintaxis básica para crear una tarea con PollJS, evidentemente nos deja establecer un intervalo de espera entre repeticiones y definir la acción que queremos ejecutar. Además se puede dar nombre a cada tarea para referenciarla posteriormente, por ejemplo, para detenerla.
Poll.stop("refresh_list");
Existe otra forma de detener una tarea, devolviendo false en la función que se pasa como acción se detiene el temporizador.

Con esta librería podemos además definir un número de reintentos máximo y una función de fallback si en ninguno de los intentos se ha detenido el temporizador.
Poll.start({
    name: "refresh_list",
    action: function(){},
    interval: 1000, 
    attempts: 5,
    fallback: function(){}
});

miércoles, 24 de agosto de 2011

Visor de PDF en HTML5

Andreas Gal (investigador de Mozilla Corporation) ha publicado la librería javascript PDF.js

Con esta librería se pueden visualizar ficheros PDF en el navegador sin plugins externos, las ventajas son claras, no hay necesidad de un programa externo, es multiplataforma, más seguro y provee de mayor interacción con el navegador.

PDF.js está todavía en proceso de desarrollo y pero el autor pretende lanzar una extensión de firefox para abrir los ficheros PDF directamente en el navegador.
Por ahora para visualizar un fichero PDF se crea dinámicamente un elemento canvas en el que se muestra la información, sin embargo, se planea migrar a SVG para permitir selección de texto, búsquedas y mayor interacción con el fichero.

Es un paso importante hacer que este tipo de ficheros se integren completamente en la web, ya algunos buscadores indexan su texto y lo incluyen en las búsquedas.

Por contra, tanto canvas como SVG están disponibles solo en los navegadores que soportan HTML5 y aún no hay un porcentaje aceptable de usuarios que usen este tipo de navegadores para aceptar esta solución como medida única.

viernes, 3 de junio de 2011

Extensión de clases en Scala

En algunos lenguajes de programación dinámicos como ruby se permite añadir funcionalidad a clases ya existentes. Cuando esto ocurre, se dice que las clases en ese lenguaje son 'abiertas'.

Un lenguaje de programación con clases abiertas añade mucha flexibilidad para el programador, sin embargo, esta flexibilidad hace que sea más difícil auditar el código.

La principal ventaja de esta técnica es poder aumentar la funcionalidad de las clases que proporciona en lenguaje. Al tener unos tipos básicos con una interfaz más rica, el código comienza a ser más sencillo y se reduce el número de líneas de código para desarrollar una funcionalidad.

En Scala, las clases no son abiertas, sin embargo, tiene un mecanismo similar con el que se pueden llegar a resultados no muy distintos.

Ejemplo:

class RomanNumber(val number:Int){
def toRoman:String = {
if(number == 1) return "I";
else if(number == 2) return "II";
else if(number == 3) return "III";
else if(number == 4) return "IV";
else if(number == 5) return "V";
else return "Unknown";
}
}

object Main extends Application{
implicit def intRomanNumber(x:Int) = new RomanNumber(x);

override def main(args: Array[String]){
println(1.toRoman);
println(3.toRoman);
println(5.toRoman);
println(6.toRoman);
}
}

En este ejemplo se crea una clase 'RomanNumber' que contiene la funcionalidad que necesitamos añadir a los enteros 'toRoman'.

El código resultaría muy redundante si cada vez que queremos usar el método 'toRoman' necesitamos crear una instancia de la clase y pasarle como argumento el entero. Algo como: new RomanNumber(4).toRoman.

Para este tipo de casos, Scala provee del mecanismo de conversión implícita, en el ejemplo el método 'intRomanNumber'.
Al definir un método como 'implicit' se llamará para hacer el correspondiente cambio de tipos como se le indique, en este caso creando una instancia de 'RomanNumber'.

El resultado final es el que aparece en el ejemplo, parece que los métodos añadidos mediante conversión implícita pertenezcan a la clase original, muy similar al caso de los lenguajes dinámicos y las clases abiertas.

sábado, 16 de abril de 2011

attr_accessor_with_default

Un pequeño tip sobre los atributos en ruby on rails, normalmente en cualquier clase se pueden declarar atributos con attr_accessor, pero, si lo que se necesita es un atributo que tenga un valor por defecto, existe una función menos conocida attr_accessor_with_default.

Un ejemplo

class Example
attr_accessor_with_default :attr, 'default message'
end

e = Example.new
e.attr
=> 'default message'

domingo, 20 de marzo de 2011

Propagación de eventos en jQuery

La primera aproximación de asignación de eventos a los elementos del DOM es la más sencilla, simplemente se establece el callback a ejecutar en el elemento que posee el evento.

$('#element').click(function(){alert('hello');})

Usando este método se disparará el evento del elemento con id 'element', después su padre, y así sucesivamente.

La segunda posibilidad es usar 'live', de esta forma todos los elementos futuros que cumplan con el selector dispararán el evento.

$('#element').live('click', function(){alert('hello');})

Esta aproximación asigna el callback a la raíz del DOM (document) de tal forma que cada vez que se dispara un evento si coincide tanto en tipo como en su selector, se dispara el callback.
Esta implementación, aún siendo muy útil puede dar lugar a comportamientos inesperados, el callback establecido con 'live' se ejecutará el último en la jerarquía de propagación del evento.

'live' no es más que una particularización de 'delegate'. 'delegate' se puede usar para hilar más fino en el establecimiento de la respuesta a eventos.

$('#parent').delegate('#element', 'click', function() { alert("hello") });

En este caso, establecemos el callback en 'parent' en lugar de en document, por lo demás el funcionamiento es similar a 'live'.
Cada vez que el evento llegue a 'parent' se comprobará si coincide tanto en tipo como en el selector, de ser cierto se dispara el callback.

'delegate' es mucho más eficiente que 'live' puesto que solo comprueba los eventos tomando como raíz el elemento que le indicamos en lugar de todo el documento como es el caso de 'live'. Aún así el problema en el orden de propagación aparece al igual que en 'live'.