jueves, 3 de febrero de 2011

Generar proyectos ruby on rails con versiones anteriores

Despué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.

Para generar un proyecto de ruby on rails con una versión anterior que tengamos instalada tan solo hay que ejecutar lo siguiente:

rails _VERSION_ proyecto

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).

rails _2.3.8_ proyecto

jueves, 20 de enero de 2011

Depuración android por red

Hay 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.

Simplemente hay que conectar el dispositivo a la misma red Wi-Fi que el PC desde el que estamos desarrollando y ejecutar el comando:

adb connect ip:5555

Donde ip es la dirección IP del dispositivo en la interfaz Wi-Fi.
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.

viernes, 7 de enero de 2011

Conocer el método desde el que una función es llamada en Java

El lenguaje de programación Java en sus últimas versiones tiene algunas construcciones que permiten introspección.

Como ejemplo en el siguiente trozo de código la función 'print' 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.

public class Ejemplo{
public static void print(){
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement e;
String str = stackTraceElements[2].getMethodName();

if(str.equals("other")){
System.out.println("Other message!");
}
else{
System.out.println("Hello world!");
}
}

public static void other(){
print();
}

public static void main(String[] args){
print();
other();
}
}

La llamada 'Thread.currentThread().getStackTrace()' devuelve un array de elementos 'StackTraceElement', cada uno de estos elementos representa una llamada de la pila de llamadas a funciones.

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 StackTraceElement.

sábado, 25 de diciembre de 2010

Javascript orientado a objetos

Debido al gran auge de la web, últimamente han surgido numerosas librerías y tutoriales acerca de como programar javascript orientado a objetos.

No es difícil encapsular código javascript simulando que se está trabajando con clases.

function Article(title, body){
this.title = title;
this.body = body;
}

var a = new Article('titulo', 'noticia')

Incluso se puede conseguir visibilidad privada para los atributos de la 'clase' que elijamos.

function Article(title, body){
this.body = body;
var _title = title;
this.getTitle = function(){
return _title;
}
this.setTitle = function(title){
_title = title;
}
}

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.

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.

De la orientación a eventos del lenguaje han surgido proyectos muy interesantes como node.js, hay que tratar de aprovechar las bondades del lenguaje, no cambiarlas a través de capas de abstracción.

miércoles, 15 de diciembre de 2010

Logger en ruby

Similar al proyecto log4j existe para ruby una librería de logging para el depurado de aplicaciones, gestión de mensajes de error, etc.

El nombre de la librería es log4r, se distribuye como gema y es fácilmente personalizable.

Para usarla tan solo hay que instancia un objeto de la clase Logger. Para dicho objeto se pueden seleccionar distintos outputters (medio de salida), en el ejemplo se muestran los mensajes tanto por salida estándar como por UDP.

Posteriormente, para cada outputter se puede elegir un formatter (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.

El ejemplo de uso de la librería.

require 'rubygems'
require 'log4r'
require 'log4r/formatter/log4jxmlformatter'
require 'log4r/outputter/udpoutputter'

include Log4r

logger = Logger.new 'mylog'

#Formatters
xmlformat = Log4jXmlFormatter.new

#Ouputters
stdout = Outputter.stdout
udpout = UDPOutputter.new 'udp', :hostname => "localhost", :port => 8888

stdout.formatter = xmlformat

logger.outputters = [stdout, udpout]


def debug(logger, txt)
logger.debug txt
end

def error(logger, txt)
logger.error txt
end


debug(logger, 'Mensaje de DEBUG')
error(logger, 'Mensaje de error')

Para más información se puede consultar la web oficial de log4r.

sábado, 20 de noviembre de 2010

Lectura de memoria entre procesos Windows

En todos los sistemas operativos modernos la memoria está protegida entre procesos.
Si un proceso accede o escribe en una posición de memoria no esperada no debe afectar a los demás procesos.

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 ReadProcessMemory y WriteProcessMemory.

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 OpenProcess.

Para buscar el proceso destino hay varias formas, en este ejemplo se usa el nombre de la ventana visible del proceso.

#include <QtCore/QCoreApplication>
#include <windows.h>

DWORD getPIDByWindowName(WCHAR* name);

int main(int argc, char *argv[]){
QCoreApplication a(argc, argv);
BYTE buffer[300];
DWORD readed;
DWORD processID = getPIDByWindowName(TEXT("Calculadora"));
HANDLE procHandle = OpenProcess(0x0010, 0, processID);
ReadProcessMemory(procHandle, (void*)0x00951558, buffer, 50, &readed);
return a.exec();
}

DWORD getPIDByWindowName(WCHAR* name){
DWORD processID;
HWND windowHandle = FindWindowW(NULL, name);
GetWindowThreadProcessId(windowHandle, &processID);
return processID;
}

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.

martes, 16 de noviembre de 2010

Ejecución de tareas asíncronas en C++ con QT

En los programas con interfaz gráfica no deben ejecutarse tareas que puedan demorarse en el mismo hilo de la interfaz.
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.

Con las librerías QT se puede solucionar de varias formas, una es creando un hilo (una clase que herede de QThread). Una forma aún más sencilla es crear un objeto QRunnable y hacer que el pool de QT lo ejecute en segundo plano.

Un ejemplo de lo segundo.

class AsynchrounousTask : public QRunnable{
protected:
QLabel *label;
public:
AsynchrounousTask(QLabel *label){
this->label = label;
}

void run(){
sleep(5); //long task;
label->setText("Done!");
}
};

Y para usarlo tan solo hay que hacer.

AsynchrounousTask *aTask = new AsynchrounousTask(ui->label);
QThreadPool::globalInstance()->start(aTask);

Aunque creamos un objeto con new 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 'setAutoDelete(false)'.

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.