tag:blogger.com,1999:blog-34993793631617034642024-03-13T00:01:21.853+01:00Blog de javiyuBlog de programación y diseño de softwarejaviyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.comBlogger147125tag:blogger.com,1999:blog-3499379363161703464.post-30661377339665066482011-12-10T09:52:00.001+01:002011-12-10T10:12:37.867+01:00Plantillas javascriptLas aplicaciones web que usan AJAX suelen seguir un patrón similar:<br />
1) Se lanza un evento javascript<br />
2) Se genera una petición al servidor<br />
3) El servidor produce código javascript de vuelta con el objetivo de añadir/eliminar HTML de la página.<br />
<br />
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.<br />
<br />
Por suerte, existe un plugin para la librería jQuery llamado <a href="https://github.com/jquery/jquery-tmpl">jQuery Templates</a> que elimina este problema.<br />
<br />
Para usar este plugin, podemos definir una plantilla javascript de la siguiente forma:<br />
<pre name="code" class="javascript"><script id="templateId" type="text/x-jquery-tmpl">
${templateText}
</script>
</pre>Siguiendo este ejemplo, con el id 'templateId' recuperaremos posteriormente la plantilla y podremos hacer la sustitución de 'templateText' con la siguiente llamada.<br />
<pre name="code" class="javascript">$("#templateId").tmpl({templateText:"Hello world"})
</pre>Como se puede ver, es similar a cualquier sistema de plantillas, se puede interpolar marcado HTML, crear condicionales:<br />
<pre name="code" class="javascript"><script id="templateId" type="text/x-jquery-tmpl">
{{if error}}
<h2>Error!</h2>
{{else}}
<h1>OK</h1>
{{/if}}
</script>
</pre><pre name="code" class="javascript">$("#templateId").tmpl({error:false})
</pre>O incluso bucles:<br />
<pre name="code" class="javascript"><script id="templateId" type="text/x-jquery-tmpl">
<h1>${title}</h1>
{{each items}}
<li>${$value}</li>
{{/each}}
</script>
</pre><pre name="code" class="javascript">$("#templateId").tmpl({title:"Titulo", items:["uno", "dos", "tres"]})
</pre><br />
<br />
<br />javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com1tag:blogger.com,1999:blog-3499379363161703464.post-68004720461243612562011-09-18T12:39:00.001+02:002011-09-18T12:39:44.063+02:00Batch processing en railsEn 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.<br />
<br />
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. <br />
<br />
Tomando como ejemplo una tabla muy grande de usuarios en la que hay que recalcular un campo para cada usuario.<br />
<pre name="code" class="ruby">User.find_each{|u| u.karma = calculate_karma(:user => u)}
</pre><i>find_each</i> 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 <i>batch_size</i>.<br />
<pre name="code" class="ruby">User.find_each(:batch_size => 200){|u| u.karma = calculate_karma(:user => u)}
</pre><i>find_each</i> se implementa usando <i>find_in_batches</i>, se puede llegar a mayor nivel de control usando esta función que devuelve directamente los grupos de entradas.<br />
<pre name="code" class="ruby">User.find_in_batches(:batch_size => 2000){|group| group.each{|u| u.karma = calculate_karma(:user => u)}}
</pre>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.<br />
<pre name="code" class="ruby">User.find_in_batches(:batch_size => 2000){|group| Process.fork{calculate_karma(:group => group)}}
</pre>javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-54952940199528958412011-09-04T12:41:00.000+02:002011-09-04T12:41:39.434+02:00Temporizadores en javascript: PollJSRealizar tareas regulares en el tiempo en una web con javascript es una tarea algo pesada. <a href="https://github.com/mtrpcic/polljs">PollJS</a> es una librería muy pequeña y sencilla que facilita algo esta tarea.<br />
<br />
Un ejemplo de una tarea regular con PollJS.<br />
<pre name="code" class="javascript">Poll.start({
name: "refresh_list",
interval: 1000,
action: function(){}
});
</pre>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.<br />
<pre name="code" class="javascript">Poll.stop("refresh_list");
</pre>Existe otra forma de detener una tarea, devolviendo <i>false</i> en la función que se pasa como acción se detiene el temporizador.<br />
<br />
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.<br />
<pre name="code" class="javascript">Poll.start({
name: "refresh_list",
action: function(){},
interval: 1000,
attempts: 5,
fallback: function(){}
});
</pre>javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-41722750955873105812011-08-24T11:27:00.005+02:002011-08-24T11:49:21.618+02:00Visor de PDF en HTML5Andreas Gal (investigador de Mozilla Corporation) ha publicado la librería javascript <a href="https://github.com/andreasgal/pdf.js">PDF.js</a>
<br />
<br />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.
<br />
<br />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.
<br />Por ahora para visualizar un fichero PDF se crea dinámicamente un elemento <span style="font-style:italic;">canvas</span> en el que se muestra la información, sin embargo, se planea migrar a <span style="font-style:italic;">SVG</span> para permitir selección de texto, búsquedas y mayor interacción con el fichero.
<br />
<br />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.
<br />
<br />Por contra, tanto <span style="font-style:italic;">canvas</span> como <span style="font-style:italic;">SVG</span> 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.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com1tag:blogger.com,1999:blog-3499379363161703464.post-59047309272056587602011-06-03T19:53:00.003+02:002011-06-03T20:09:37.889+02:00Extensión de clases en ScalaEn 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'. <br /><br />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.<br /><br />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.<br /><br />En Scala, las clases no son abiertas, sin embargo, tiene un mecanismo similar con el que se pueden llegar a resultados no muy distintos.<br /><br />Ejemplo:<br /><pre name="code" class="ruby"><br />class RomanNumber(val number:Int){<br /> def toRoman:String = {<br /> if(number == 1) return "I";<br /> else if(number == 2) return "II";<br /> else if(number == 3) return "III";<br /> else if(number == 4) return "IV";<br /> else if(number == 5) return "V"; <br /> else return "Unknown";<br /> } <br />}<br /><br />object Main extends Application{<br /> implicit def intRomanNumber(x:Int) = new RomanNumber(x);<br /><br /> override def main(args: Array[String]){<br /> println(1.toRoman);<br /> println(3.toRoman);<br /> println(5.toRoman);<br /> println(6.toRoman);<br /> }<br />}<br /></pre><br />En este ejemplo se crea una clase 'RomanNumber' que contiene la funcionalidad que necesitamos añadir a los enteros 'toRoman'.<br /><br />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: <span style="font-style:italic;">new RomanNumber(4).toRoman</span>.<br /><br />Para este tipo de casos, Scala provee del mecanismo de conversión implícita, en el ejemplo el método 'intRomanNumber'.<br />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'.<br /><br />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.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-8011146383985754422011-04-16T10:28:00.002+02:002011-04-16T10:34:02.475+02:00attr_accessor_with_defaultUn pequeño tip sobre los atributos en ruby on rails, normalmente en cualquier clase se pueden declarar atributos con <span style="font-style:italic;">attr_accessor</span>, pero, si lo que se necesita es un atributo que tenga un valor por defecto, existe una función menos conocida <span style="font-style:italic;">attr_accessor_with_default</span>.<br /><br />Un ejemplo<br /><pre name="code" class="ruby"><br />class Example<br /> attr_accessor_with_default :attr, 'default message'<br />end<br /><br />e = Example.new<br />e.attr<br />=> 'default message'<br /></pre>javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-82941076381429172542011-03-20T11:35:00.003+01:002011-03-20T12:03:30.488+01:00Propagación de eventos en jQueryLa 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.<br /><pre name="code" class="javascript"><br />$('#element').click(function(){alert('hello');})<br /></pre><br />Usando este método se disparará el evento del elemento con id 'element', después su padre, y así sucesivamente.<br /><br />La segunda posibilidad es usar 'live', de esta forma todos los elementos futuros que cumplan con el selector dispararán el evento.<br /><pre name="code" class="javascript"><br />$('#element').live('click', function(){alert('hello');})<br /></pre><br />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. <br />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.<br /><br />'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.<br /><pre name="code" class="javascript"><br />$('#parent').delegate('#element', 'click', function() { alert("hello") });<br /></pre><br />En este caso, establecemos el callback en 'parent' en lugar de en document, por lo demás el funcionamiento es similar a 'live'. <br />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.<br /><br />'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'.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com1tag:blogger.com,1999:blog-3499379363161703464.post-49945909525707591172011-02-03T22:04:00.004+01:002011-02-03T22:08:46.761+01:00Generar proyectos ruby on rails con versiones anterioresDespués del cambio de versión de ruby on rails de la rama 2 a la 3, surge un caso muy típico, tener instalado rails 3 y querer generar un proyecto con la versión 2.<br /><br />Para generar un proyecto de ruby on rails con una versión anterior que tengamos instalada tan solo hay que ejecutar lo siguiente:<br /><pre name="code" class="ruby"><br />rails _VERSION_ proyecto<br /></pre><br />Donde VERSION es la numeración específica de la versión de rails, por ejemplo, para crear un proyecto con la versión 2.3.8 (actualmente la última de la rama 2).<br /><pre name="code" class="ruby"><br />rails _2.3.8_ proyecto<br /></pre>javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com1tag:blogger.com,1999:blog-3499379363161703464.post-60442926631595558422011-01-20T20:56:00.003+01:002011-01-20T21:04:07.962+01:00Depuración android por redHay dispositivos android que no permiten la depuración a través del conector USB, aún así, es posible usarlos para desarrollo usando la conectividad por Wi-Fi.<br /><br />Simplemente hay que conectar el dispositivo a la misma red Wi-Fi que el PC desde el que estamos desarrollando y ejecutar el comando:<br /><pre name="code" class="c"><br />adb connect ip:5555<br /></pre><br />Donde ip es la dirección IP del dispositivo en la interfaz Wi-Fi.<br />A partir de ahí se puede usar adb igual que cuando está conectada la depuración USB, se puede usar la shell, la transferencia de ficheros, etc, incluso el android SDK sin necesidad de cables.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-61824673588873673672011-01-07T19:17:00.003+01:002011-01-07T19:30:35.751+01:00Conocer el método desde el que una función es llamada en JavaEl lenguaje de programación Java en sus últimas versiones tiene algunas construcciones que permiten introspección.<br /><br />Como ejemplo en el siguiente trozo de código la función '<span style="font-style:italic;">print</span>' tiene un comportamiento u otro dependiendo de que método le llama. En general esto no es una buena práctica de programación pero sirve como ejemplo ilustrativo.<br /><pre name="code" class="java"><br />public class Ejemplo{ <br /> public static void print(){<br /> StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();<br /> StackTraceElement e;<br /> String str = stackTraceElements[2].getMethodName();<br /> <br /> if(str.equals("other")){<br /> System.out.println("Other message!");<br /> } <br /> else{<br /> System.out.println("Hello world!"); <br /> } <br /> }<br /> <br /> public static void other(){<br /> print();<br /> }<br /> <br /> public static void main(String[] args){<br /> print();<br /> other();<br /> }<br />}<br /></pre><br />La llamada '<span style="font-style:italic;">Thread.currentThread().getStackTrace()</span>' devuelve un array de elementos '<span style="font-style:italic;">StackTraceElement</span>', cada uno de estos elementos representa una llamada de la pila de llamadas a funciones.<br /><br />En el ejemplo anterior se consulta el nombre del método, pero se pueden extraer más datos, más información en el javadoc de <a href="http://download.oracle.com/javase/6/docs/api/java/lang/StackTraceElement.html">StackTraceElement</a>.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-74005569296511284112010-12-25T11:09:00.002+01:002010-12-25T11:29:39.910+01:00Javascript orientado a objetosDebido al gran auge de la web, últimamente han surgido numerosas librerías y tutoriales acerca de como programar javascript orientado a objetos.<br /><br />No es difícil encapsular código javascript simulando que se está trabajando con clases.<br /><pre name="code" class="javascript"><br />function Article(title, body){<br /> this.title = title;<br /> this.body = body;<br />}<br /><br />var a = new Article('titulo', 'noticia')<br /></pre><br />Incluso se puede conseguir visibilidad privada para los atributos de la 'clase' que elijamos.<br /><pre name="code" class="javascript"><br />function Article(title, body){<br /> this.body = body;<br /> var _title = title;<br /> this.getTitle = function(){<br /> return _title;<br /> }<br /> this.setTitle = function(title){<br /> _title = title;<br /> } <br />}<br /></pre><br />Sin embargo, en mi opinión todas estas aproximaciones conducen a escribir código javascript poco natural. Javascript fue pensado como un lenguaje de programación basado en prototipos y su flujo principal de ejecución es orientado a eventos.<br /><br />Está basado en prototipos, la encapsulación, las 'clases' se obtienen a partir de la clonación de objetos y no de una estructura tan rígida como la orientación a objetos. Esto hace al lenguaje mucho más propicio para las tareas que fue pensado.<br /><br />De la orientación a eventos del lenguaje han surgido proyectos muy interesantes como <a href="http://nodejs.org/">node.js</a>, hay que tratar de aprovechar las bondades del lenguaje, no cambiarlas a través de capas de abstracción.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-17918854869060095912010-12-15T23:37:00.002+01:002010-12-15T23:45:39.466+01:00Logger en rubySimilar al proyecto <span style="font-style:italic;">log4j</span> existe para ruby una librería de logging para el depurado de aplicaciones, gestión de mensajes de error, etc.<br /><br />El nombre de la librería es <span style="font-style:italic;">log4r</span>, se distribuye como gema y es fácilmente personalizable.<br /><br />Para usarla tan solo hay que instancia un objeto de la clase <span style="font-style:italic;">Logger</span>. Para dicho objeto se pueden seleccionar distintos <span style="font-style:italic;">outputters</span> (medio de salida), en el ejemplo se muestran los mensajes tanto por salida estándar como por UDP.<br /><br />Posteriormente, para cada <span style="font-style:italic;">outputter</span> se puede elegir un <span style="font-style:italic;">formatter</span> (formato de la salida). En el ejemplo la salida por UDP será en el formato por defecto mientras que la salida estándar será en XML.<br /><br />El ejemplo de uso de la librería.<br /><pre name="code" class="ruby"><br />require 'rubygems'<br />require 'log4r'<br />require 'log4r/formatter/log4jxmlformatter'<br />require 'log4r/outputter/udpoutputter'<br /><br />include Log4r<br /><br />logger = Logger.new 'mylog'<br /><br />#Formatters<br />xmlformat = Log4jXmlFormatter.new<br /><br />#Ouputters<br />stdout = Outputter.stdout<br />udpout = UDPOutputter.new 'udp', :hostname => "localhost", :port => 8888<br /><br />stdout.formatter = xmlformat<br /><br />logger.outputters = [stdout, udpout]<br /><br /><br />def debug(logger, txt)<br /> logger.debug txt<br />end<br /><br />def error(logger, txt)<br /> logger.error txt<br />end<br /><br /><br />debug(logger, 'Mensaje de DEBUG')<br />error(logger, 'Mensaje de error')<br /></pre><br />Para más información se puede consultar la web oficial de <a href="http://log4r.rubyforge.org/manual.html">log4r</a>.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com1tag:blogger.com,1999:blog-3499379363161703464.post-86600899631201824062010-11-20T20:10:00.003+01:002010-11-20T20:27:38.755+01:00Lectura de memoria entre procesos WindowsEn todos los sistemas operativos modernos la memoria está protegida entre procesos. <br />Si un proceso accede o escribe en una posición de memoria no esperada no debe afectar a los demás procesos.<br /><br />A pesar de este planteamiento, en Windows es posible leer o escribir zonas de memoria entre procesos, para ello están las funciones del API <span style="font-style:italic;">ReadProcessMemory</span> y <span style="font-style:italic;">WriteProcessMemory</span>.<br /><br />El primer paso es encontrar el PID del proceso en el que estamos interesados y después debe obtenerse un handle con la función <span style="font-style:italic;">OpenProcess</span>.<br /><br />Para buscar el proceso destino hay varias formas, en este ejemplo se usa el nombre de la ventana visible del proceso.<br /><pre name="code" class="c"><br />#include <QtCore/QCoreApplication><br />#include <windows.h><br /><br />DWORD getPIDByWindowName(WCHAR* name);<br /><br />int main(int argc, char *argv[]){<br /> QCoreApplication a(argc, argv);<br /> BYTE buffer[300];<br /> DWORD readed;<br /> DWORD processID = getPIDByWindowName(TEXT("Calculadora"));<br /> HANDLE procHandle = OpenProcess(0x0010, 0, processID);<br /> ReadProcessMemory(procHandle, (void*)0x00951558, buffer, 50, &readed);<br /> return a.exec();<br />}<br /><br />DWORD getPIDByWindowName(WCHAR* name){<br /> DWORD processID;<br /> HWND windowHandle = FindWindowW(NULL, name);<br /> GetWindowThreadProcessId(windowHandle, &processID);<br /> return processID;<br />}<br /></pre><br />Gracias al uso de estas funciones del API se abre una nueva posibilidad de comunicación entre procesos, sin embargo, abre también un grave riesgo de seguridad. Entre otros usos, modificando la memoria de los procesos de antivirus o cortafuegos se pueden inutilizar dando una falsa sensación se seguridad.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-8833559832602788622010-11-16T20:34:00.004+01:002010-11-16T20:53:19.983+01:00Ejecución de tareas asíncronas en C++ con QTEn los programas con interfaz gráfica no deben ejecutarse tareas que puedan demorarse en el mismo hilo de la interfaz.<br />Esto ocurre muy a menudo si en el evento 'click' de un botón se hace una lectura/escritura de un fichero o una base de datos.<br /><br />Con las librerías QT se puede solucionar de varias formas, una es creando un hilo (una clase que herede de <span style="font-style:italic;">QThread</span>). Una forma aún más sencilla es crear un objeto <span style="font-style:italic;">QRunnable</span> y hacer que el pool de QT lo ejecute en segundo plano.<br /><br />Un ejemplo de lo segundo.<br /><pre name="code" class="c"><br />class AsynchrounousTask : public QRunnable{<br /> protected:<br /> QLabel *label;<br /> public:<br /> AsynchrounousTask(QLabel *label){<br /> this->label = label;<br /> }<br /><br /> void run(){<br /> sleep(5); //long task;<br /> label->setText("Done!");<br /> }<br />};<br /></pre><br />Y para usarlo tan solo hay que hacer.<br /><pre name="code" class="c"><br /> AsynchrounousTask *aTask = new AsynchrounousTask(ui->label);<br /> QThreadPool::globalInstance()->start(aTask);<br /></pre><br />Aunque creamos un objeto con <span style="font-style:italic;">new</span> no hay que preocuparse por su destrucción, al terminar su ejecución a través del pool se liberará de forma automática. Si preferimos que no se libere de forma automática tan solo hay que llamar al método '<span style="font-style:italic;">setAutoDelete(false)</span>'.<br /><br />Ejecutando las tareas más pesadas de la aplicación de esta forma no se bloqueará la aplicación en ningún momento y siempre responderá a las nuevas peticiones que el usuario haga.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-20621888554502986072010-11-10T20:38:00.004+01:002010-11-10T20:50:02.914+01:00Compilación de ejecutable con Qt CreatorCuando creamos una aplicación con Qt Creator en Windows es necesario incluir los ficheros dll de Qt para que la aplicación funcione correctamente.<br /><br />En ocasiones este no es el comportamiento deseado, se puede generar un fichero ejecutable autónomo (sin necesidad de ninguna librería dll externa) ejecutando el siguiente comando:<br /><pre name="code" class="c"><br />qmake -nodepend -o Makefile project.pro<br /></pre><br />Si no se encuentra el programa qmake hay que añadirlo al PATH, la instalación por defecto de QT Creator no lo hace. <br />Una vez ejecutado el comando anterior, al compilar obtendremos un ejecutable con toda la funcionalidad incluida, sin necesidad de incluir ningún fichero dll.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com1tag:blogger.com,1999:blog-3499379363161703464.post-38143638085384620912010-10-17T10:48:00.004+02:002010-10-17T11:06:58.900+02:00Anidamiento de módulos en rubyTal y como ocurre en python con los decoradores, cuando se programa un módulo en ruby debería dejarse la puerta abierta a que no fuera el único.<br /><br />En el siguiente ejemplo tenemos dos módulos (<span style="font-style:italic;">Printable</span> y <span style="font-style:italic;">Serializable</span>), ambos métodos se deben poder combinar en cualquier orden y pudiendo aparecer uno, ninguno o ambos.<br /><br />La clave para que un mismo método se ejecute en la clase y en cada uno de sus módulos, es la llamada a <span style="font-style:italic;">super</span>.<br /><br />En otros lenguajes esto no sería correcto, puesto que los módulos <span style="font-style:italic;">Printable</span> y <span style="font-style:italic;">Serializable</span> no son superclase de la clase <span style="font-style:italic;">Test</span>, pero en ruby, <span style="font-style:italic;">super</span> no llama exactamente a la superclase, sino que repite el mismo método que se está ejecutando obviando la definición actual.<br /><pre name="code" class="ruby"><br />module Printable<br /> def print_method<br /> super<br /> puts "I'm printable"<br /> end<br />end<br /><br />module Serializable<br /> def print_method<br /> super<br /> puts "I'm serializable"<br /> end<br />end<br /><br /><br />class Test <br /> include Printable<br /> include Serializable<br /><br /> def method_missing(method, *args, &block)<br /> super if method.to_s != 'print_method'<br /> end<br /><br /> def print_method<br /> super<br /> puts "I'm object of Test class"<br /> end<br /> <br />end<br /><br />t = Test.new<br />t.print_method<br /></pre><br />Con este planteamiento hay un problema añadido, al final de la cadena de llamadas a <span style="font-style:italic;">print_method</span> estará la clase de la que hereda <span style="font-style:italic;">Test</span>, y esta clase no tiene porqué tener implementado <span style="font-style:italic;">print_method</span>.<br /><br />Para solucionarlo en este caso se redefine el <span style="font-style:italic;">method_missing</span>, cuando llegue el momento de ejecutar el método en alguna clase/módulo que no lo entienda, se corta la cadena de ejecuciones.<br /><pre name="code" class="ruby"><br />I'm printable<br />I'm serializable<br />I'm object of Test class<br /></pre>javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-28299513976253243532010-09-17T19:35:00.002+02:002010-09-17T19:47:46.789+02:00Conversión implícita de tiposEs común escribir nuevas clases que expandan a las básicas del lenguaje.<br /><br />Uno de los problemas que nos podemos encontrar cuando hacemos esto es la conversión de tipos.<br /><br />Si por ejemplo creamos una nueva clase para manejar cadenas, el código se llenará rápidamente de castings para convertir las cadenas nativas del lenguaje a nuestra implementación. Esto ocurre sobre todo en lenguajes fuertemente tipados.<br /><br />C# provee una solución bastante elegante, la conversión implícita de tipos.<br /><br />Para mostrar el uso de esta característica se muestra una clase con dos tipos, una cadena y un entero y sus declaraciones de conversiones implícitas.<br /><pre name="code" class="c"><br />public class MyClass<br />{<br /> private string str { get; set; }<br /> private int number { get; set; }<br /><br /> public static implicit operator MyClass(string s)<br /> {<br /> MyClass ms = new MyClass();<br /> ms.str = s;<br /> return ms;<br /> }<br /><br /> public static implicit operator MyClass(int i)<br /> {<br /> MyClass ms = new MyClass();<br /> ms.number = i;<br /> return ms;<br /> }<br /><br /> public string getStr()<br /> {<br /> return str;<br /> }<br /><br /> public int getNumber()<br /> {<br /> return number;<br /> }<br />}<br /></pre><br />Declarando un operador estático, implícito y público se consigue la sintaxis siguiente para la conversión de tipos.<br /><pre name="code" class="c"><br />MyClass ms1 = "hello";<br />MyClass ms2 = 2;<br /><br />Console.WriteLine(ms1.getStr());<br />Console.WriteLine(ms2.getNumber());<br /></pre><br />En el ejemplo se puede ver que no es necesaria ninguna conversión, y se pasan tanto la cadena "hello" como el entero 2 a tipo <span style="font-style:italic;">MyClass</span>.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com1tag:blogger.com,1999:blog-3499379363161703464.post-70421935254808337742010-09-12T10:32:00.004+02:002010-09-12T11:04:52.742+02:00Extension methods en c#En algunos lenguajes dinámicos como ruby las clases se denominan "abiertas". <br />Esto significa que a cualquier clase se le puede añadir nuevos métodos o funcionalidades en tiempo de ejecución.<br /><br />Los lenguajes fuertemente tipados no suelen ofrecer tanta libertad, pero se disponen de otras herramientas.<br /><br />En C#, se pueden definir clases parciales, lo que significa que se puede definir el comportamiento de la clase en varias etapas.<br /><pre name="code" class="c"><br />public partial class PartialClass<br />{<br /> public static void method1()<br /> {<br /> Console.WriteLine("method1"); <br /> }<br />}<br />...<br />public partial class PartialClass<br />{<br /> public static void method2()<br /> {<br /> Console.WriteLine("method2");<br /> }<br />}<br /></pre><br />Manteniendo las clases como parciales en cualquier momento se puede añadir funcionalidad a una clase existente fuera de su definición original.<br /><br />Este método es útil tan solo para las clases que programamos, pero si queremos extender una librería externa o las clases del propio lenguaje las clases parciales no son de gran ayuda.<br /><br />C# tiene en cambio una posibilidad más interesante, los "extension methods".<br /><pre name="code" class="c"><br />public static class ExtensionMethods<br />{<br /> public static string withDot(this string str)<br /> {<br /> return str + ".";<br /> }<br />}<br />...<br />string str = "text ";<br />str.withDot();<br /></pre><br />Con el código anterior se le añade a la clase string el nuevo método (<span style="font-style:italic;">withDot</span>). <br />Para hacer lo mismo sin "extension methods" habría sido necesario crear una nueva clase que heredara de <span style="font-style:italic;">string </span>y añadirle el método <span style="font-style:italic;">withDot</span>.<br /><br />Gracias a los "extension methods" se puede evitar crear clases intermedias para extender funcionalidades de las ya existentes.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-65740877112649164512010-08-28T17:09:00.003+02:002010-08-28T17:22:04.952+02:00Implementación explícita de interfaces en C#Por diversas razones como la colisión de nombres o simplemente por diseño, puede que necesitemos mayor granularidad para distinguir que método de que interfaz estamos definiendo.<br /><br />Supongamos que tenemos el caso de una clase que implementa dos interfaces tal y como sigue:<br /><pre name="code" class="c"><br />public interface IInterface1<br />{<br /> int method();<br /> int method1();<br />}<br /><br />public interface IInterface2<br />{<br /> int method();<br /> int method2();<br />}<br /><br />public class ExampleClass : IInterface1, IInterface2<br />{<br /> public int method() { return 1; }<br /> public int method1() { return 1; }<br /> public int method2() { return 2; }<br /><br />}<br /></pre><br />En este caso, el método <span style="font-style:italic;">method</span> está presente en las dos interfaces y lo definimos en la clase.<br /><br />Si necesitáramos distinguir alguno de los casos se podría usar la implementación explícita de interfaces.<br /><pre name="code" class="c:nocontrols"><br />public class ExampleClass : IInterface1, IInterface2<br />{<br /> public int method() { return 1; }<br /> public int method1() { return 1; }<br /> public int method2() { return 2; }<br /><br /> int IInterface1.method() { return 1; }<br /> int IInterface2.method() { return 2; }<br /><br />}<br /><br /><br />public partial class Form1 : Form<br />{<br /> public Form1()<br /> {<br /> InitializeComponent();<br /><br /> ExampleClass example = new ExampleClass();<br /> IInterface1 i1 = (IInterface1)example;<br /> IInterface2 i2 = (IInterface2)example;<br /><br /> MessageBox.Show("Interface 1: " + i1.method());<br /> MessageBox.Show("Interface 2: " + i2.method());<br /> }<br />}<br /></pre><br />Esto devolvería como resultados 1 y 2 respectivamente. Como vemos, a pesar de realizar la implementación explícita de ambas interfaces se sigue pudiendo implementar de la forma tradicional como caso base.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-76358682572605054662010-07-21T22:30:00.001+02:002010-07-21T22:32:36.794+02:00Internacionalización con QTLa librería QT está desarrollada de tal forma que las aplicaciones<br />que estén hechas usando su API pueden internacionalizarse de forma bastante<br />fácil.<br /><br />En primer lugar todas las cadenas de la aplicación deben sustituirse por llamadas<br />a la función <span style="font-style:italic;">tr</span>.<br /><pre name="code" class="c"><br />QObject::tr("cadena");<br /></pre><br />La cadena que pasemos a la función <span style="font-style:italic;">tr</span> servirá de índice para las cadenas<br />definitivas en los distintos idiomas.<br /><br />Después se debe añadir una entrada en el fichero de proyecto (.pro) con los ficheros<br />que se deben generar para cada idioma de las traducciones, con extensión .ts.<br /><pre name="code" class="c"><br />TRANSLATIONS = en.ts es.ts<br /></pre><br />Los ficheros se generarán al ejecutar el comando:<br /><pre name="code" class="c"><br />lupdate proyecto.pro<br /></pre><br />Estos ficheros .ts se pueden editar con QT Linguist, una vez introducidas todas las<br />traducciones, se pueden exportar mediante la opción <i>Release</i>, esto generaráa<br />unos ficheros .qm.<br /><br />Posteriormente hay que crear un fichero de recursos que contenga los ficheros .qm<br />de traducciones.<br /><br />Para obtener el idioma del equipo en el que se está ejecutándo la aplicación se puede<br />hacer lo siguiente<br /><pre name="code" class="c"><br />QString locale = QLocale::system().name();<br /></pre><br />Para que las traducciones se carguen hay que instanciar la clase <span style="font-style:italic;">QTranslator</span> y pasársela<br />a la aplicación.<br /><pre name="code" class="c"><br />QTranslator translator;<br />translator.load(locale, ":/");<br />a.installTranslator(&translator);<br /></pre><br />La ruta ":/" se refiere al prefijo introducido en el fichero de recursos.<br /><br />Tras estos pasos las cadenas de la aplicación aparecerán traducidas dependiendo del idioma<br />del equipo en el que se esté ejecutándo.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com1tag:blogger.com,1999:blog-3499379363161703464.post-55911916816743540542010-07-15T22:18:00.002+02:002010-07-15T22:37:00.106+02:00Como implementar interfaces en C++C++ por si solo no trata las interfaces como un concepto diferenciado. Sin embargo se puede trabajar con interfaces tipo Java o C# aprovechándose de la heréncia múltiple creando clases abstractas.<br /><br />En el siguiente ejemplo las clases <span style="font-style:italic;">ClassA</span> y <span style="font-style:italic;">ClassB</span> implementan la interfaz <span style="font-style:italic;">Interface</span>, para ello tan solo tienen que redefinir el método <span style="font-style:italic;">method</span>.<br /><pre name="code" class="c"><br />class Interface{<br /> public:<br /> virtual int method(int param) = 0;<br /> virtual ~Interface(){};<br />};<br /><br />class ClassA : public Interface{<br /> public:<br /> int method(int param){return param+1;}<br />};<br /><br />class ClassB : public Interface{<br /> public:<br /> int method(int param){return param+2;}<br />};<br /></pre><br />Todos los usos que se le dan normalmente a las interfaces siguen siendo válidos con esta aproximación, con una salvedad, si queremos pasar la interfaz como parámetro a una función normalmente se haría como sigue.<br /><pre name="code" class="c"><br />std::string function(Interface i){<br /> std::string str;<br /><br /> int number = i.method(1);<br /> if(number==2){str = "ClassA";}<br /> else if(number==3){str = "ClassB";}<br /><br /> return str;<br />}<br /></pre><br />Sin embargo, si hacemos esos el compilador protestará con un error similar a: "<span style="font-style:italic;">cannot declare parameter 'i' to be of abstract type 'interface'</span>". <br /><br />¿Por qué?<br />Esto ocurre porque por defecto en C++ los parámetros se pasan por valor, el objeto 'i' es imposible de crear ya que es de un tipo abstracto, el compilador no puede instanciarlo.<br /><br />¿Qué solución hay?<br />Pasarlo como referencia, con una definición como la siguiente.<br /><pre name="code" class="c"><br />std::string function(Interface &i)<br /></pre><br />Si queremos asegurarnos que el parámetro no se modifica, habría que pasarlo como referencia constante.<br /><pre name="code" class="c"><br />std::string function(const Interface &i)<br /></pre><br />Esto plantea un nuevo problema, generando un error de compilación similar a: "<span style="font-style:italic;">passing 'const Interface' as 'this' argument of 'virtual int Interface::method(int)' discards qualifiers</span>".<br /><br />No se puede llamar a una función no constante desde un objeto constante. Para solucionarlo los métodos de la interfaz deberían ser constantes, quedando como sigue.<br /><pre name="code" class="c"><br />class Interface{<br /> public:<br /> virtual int method(int param) const = 0;<br /> virtual ~Interface(){};<br />};<br /><br />class ClassA : public Interface{<br /> public:<br /> int method(int param) const{return param+1;};<br />};<br /><br />class ClassB : public Interface{<br /> public:<br /> int method(int param) const{return param+2;};<br />};<br /></pre>javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com2tag:blogger.com,1999:blog-3499379363161703464.post-9197666478348396172010-07-05T21:06:00.003+02:002010-07-05T21:16:49.350+02:00Definición de funciones parcialesLa definición de funciones parciales (<a href="http://es.wikipedia.org/wiki/Currificaci%C3%B3n">currificación</a>) es una técnica de la programación funcional poco extendida.<br /><br />A una función parcial con dos parámetros, se le puede pasar tan solo una variable, obteniendo como resultado de la ejecución otra función con una variable a la que ya se le a aplicado el primer parámetro. Por ejemplo, scala tiene una sintaxis muy simple para llevar a cabo esta técnica.<br /><pre name="code" class="c"><br />def function(x:Int)(y:Int) = x+y<br /><br />val partial = function(3)_<br /><br />partial(4)<br /></pre><br />Como resultado de la evaluación parcial (es obligatorio en scala acabarla con '_') se obtiene una función que solo necesita el segundo parámetro para ser evaluada.<br /><br />Esta técnica puede servir para ahorrar código, modelar inyección de dependencia o reducir interfaces de un conjunto de funciones haciéndolas más sencillas.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com1tag:blogger.com,1999:blog-3499379363161703464.post-58984900343075875092010-06-30T22:26:00.002+02:002010-06-30T22:39:34.030+02:00Creación de servidores en javascriptAunque javascript está diseñado para ejecutarse en el cliente al cargar páginas web, no está limitado a este ámbito.<br />Existe un proyecto llamado <a href="http://en.wikipedia.org/wiki/CommonJS">CommonJS</a> que amplia la funcionalidad del lenguaje haciéndole poder interactuar con el sistema como un lenguaje más.<br /><br /><a href="http://nodejs.org/">node.js</a> es un framework para la creación de servidores que se apoya en la librería CommonJS.<br />Está construido completamente siguiendo la filosofía "event-loop" y todas las operaciones I/O se realizan de manera asíncrona para una buen aprovechamiento de la concurrencia del sistema.<br /><br />Así pues, node.js permite crear servidores optimizados de forma sencilla desde un lenguaje dinámico como javascript, un ejemplo muy simple de un servidor creado con node.js es el siguiente:<br /><pre name="code" class="javascript"><br />var sys = require('sys');<br />var net = require('net');<br /><br />var acc = 0;<br /><br />net.createServer(function (socket) {<br /> socket.setEncoding("utf8");<br /> socket.addListener("connect", function () {<br /> socket.write("Accumulator server\r\n");<br /> socket.write("Accumulator value: " + acc + '\n');<br /> });<br /> socket.addListener("data", function (data) {<br /> var input = parseInt(data);<br /> if(!isNaN(input)){acc += parseInt(data);}<br /> socket.write("Accumulator value: " + acc + '\n');<br /> });<br /> socket.addListener("end", function () {<br /> socket.end();<br /> });<br />}).listen(8888, "127.0.0.1");<br /></pre><br />Se puede consultar en mayor profundidad el <a href="http://nodejs.org/api.html">API</a> oficial.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-23451990710789282982010-06-16T22:25:00.004+02:002010-06-16T22:43:17.596+02:00Nuevos tipos de formularios en html5Con el salto a la nueva versión de html se van añadir nuevos tipos de entradas posibles a los formularios.<br />Por ejemplo, crear un 'slider' para seleccionar un rango se limitará a dar el tipo <span style="font-style:italic;">range</span> a un <span style="font-style:italic;">input</span>.<br /><pre name="code" class="c"><br /><input type="range" min="0" max="100" step="2"><br /></pre><br />Este componente enriquece la interfaz de usuario, hay otros aún más útiles, por ejemplo el siguiente indica que la entrada debe ser de tipo numérico, esto puede ayudar a dispositivos móviles con pantallas reducidas a desplegar tan solo un teclado con números, aprovechando mejor el espacio.<br /><pre name="code" class="c"><br /><input required type="number" min="0" step="1" ><br /></pre><br />También sirve el tipo email para idénticos propósitos. Además de esta forma los navegadores pueden añadir mayor integración (si conocen que el tipo de entrada es email pueden sugerir los de nuestra libreta de direcciones).<br /><br />Otro tipo de entradas muy comunes son las de fecha, en buscadores de reservas de hoteles, vuelos, etc. La mayoría de webmaster solucionan el problema de mostrar un calendario con javascript.<br />En html5 se deja este la responsabilidad de representar estos tipos de entradas a los navegadores, habiendo <span style="font-style:italic;">inputs</span> de tipo <span style="font-style:italic;">date, month, week, time</span>...<br /><br />Para más <a href="http://www.w3.org/TR/html5/forms.html">información</a>.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0tag:blogger.com,1999:blog-3499379363161703464.post-44941588484226354882010-06-13T11:03:00.004+02:002010-06-13T11:20:13.960+02:00Hot swapping en erlangHot swapping en un entorno con múltiples procesos distribuidos se refiere a la actualización de uno de esos procesos sin parar en ningún momento el sistema.<br /><br />Si se encuentra algún error en el software, o se necesita añadir nueva funcionalidad, el proceso afectado encola las peticiones nuevas que van llegando, actualiza su código y con el nuevo código sigue atendiendo a las peticiones que tenía encoladas. Los demás procesos del sistema no notan nada de este cambio.<br /><br />En muchas de las tecnologías usadas hoy en día, todo este proceso es bastante complejo, sin embargo, en erlang es trivial ya que lo soporta de forma nativa el lenguaje.<br /><br />Supongamos dos procesos, uno que sirve datos.<br /><pre name="code" class="c"><br />-module(data).<br />-export([get/0, version/0]).<br /><br />get() -> 42.<br /><br />version() -> 1.<br /></pre><br />Y otro que los consume.<br /><pre name="code" class="c"><br />-module(consumer).<br />-compile(export_all).<br /><br />start() -> spawn(fun() -> loop() end).<br /><br />loop() -><br /> sleep(),<br /> io:format("Value: ~p at version: ~p~n", [data:get(), data:version()]),<br /> loop().<br /><br /><br />sleep() -><br /> receive<br /> after 1000 -> true<br /> end.<br /></pre><br />El proceso consumidor irá mostrando cada segundo los datos que le manda el otro proceso. En el momento que se necesite cambiar la funcionalidad del proceso creador de datos, simplemente se recompila y el consumidor el único cambio que notará es el valor que tienen los nuevos datos.<br /><pre name="code" class="c"><br />1> c(data).<br />{ok,data}<br />2> c(consumer).<br />{ok,consumer}<br />3> consumer:start().<br /><0.53.0><br />Value: 42 at version: 1<br />Value: 42 at version: 1<br />Value: 42 at version: 1<br />Value: 42 at version: 1<br />Value: 42 at version: 1<br />...<br />c(data).<br />{ok,data}<br />Value: 43 at version: 2<br />Value: 43 at version: 2<br />Value: 43 at version: 2<br />Value: 43 at version: 2<br />...<br /></pre><br />En entornos críticos o en los que el sistema completo tarda mucho tiempo en arrancar, esto permite actualizar código sin que haya que mantener el servicio parado mientras se actualilza.javiyuhttp://www.blogger.com/profile/16257073535399021686noreply@blogger.com0