lunes, febrero 20, 2012

VFP: Manejador de eventos en tiempo de ejecucion

Hay muchas situaciones en las que terminamos necesitando que una instancia de una clase propia pueda ejecutar codigo arbitrario en uno o mas de sus eventos, como por ejemplo en clases que se instancian en tiempo de ejecucion en lugar de hacerlo en tiempo de diseño.

Habiéndome topado con estos casos muchas veces, hace unos dias terminé escribiendo una clase que me permite añadir un manejador de eventos dinámicos a cualquier clase de forma sencilla. El primer paso es crear un manejador de eventos en la clase. Para esto le añadimos una propiedad que contendrá la instancia del manejador de eventos, la cual es creada en el constructor de la clase (evento Init):

THIS.Events = CREATEOBJECT("VEEventHandler")

Lo siguiente es definir los eventos que estarán disponibles y la forma de manejar los mismos. La clase permite dos formas de manejar los eventos declarados cuando estos son invocados.

Usando una clase controller
Consiste en asociar un metodo de una clase controladora al evento declarado de modo que, cuando se invoque el evento indicado este procesa a invocar el metodo indicado en la clase controladora. La principal ventaja de este metodo es que la asociacion entre el evento y su controlador puede ser modificada sin que esto afecte el código existente. La forma de definir estos eventos seria así:

THIS.Events.Add("sayHello","Hello",oController)

Lo que estamos diciendo aqui es:
define un evento llamado "sayHello" el cual, cuando sea invocado, llamará al método "Hello" del objeto "oController".

Usando codigo dinámico
Consiste en asociar un codigo VFP válido al evento, de modo que cuando este sea invocado se ejecute el método asociado al evento. La ventaja principal de este método es que no necesitamos de un segundo objeto que maneje los eventos y ademas el código asociado al evento puede cambiar dinámicamente sin afectar el resto del codigo de la aplicación. La forma de definir estos eventos es:

THIS.Events.Add("sayHi",cSayHiCode)


Como invocar los eventos
Una vez definidos los eventos que estarán disponibles en la clase, lo único que queda es invocarlos cuando sea necesario. La clase ofrece dos formas de invocar estos eventos:

Invocación directa
Consiste en invocar el evento directamente por su nombre:

miObjeto.Events.sayHello.Raise("World!")

El método Raise acepta hasta 10 parámetros, los cuales son pasados al método del controller asociado al evento, o a la sentencia PARAMETERS o LPARAMETERS del código asociado al mismo.

Invocación indirecta
Esta forma permite invocar el evento indirectamente, mediante un string que identifica el nombre del evento:

miObjeto.Events.Raise("sayHello","Mundo!")

El primer parámetro del metodo Raise recibe el nombre del evento a invocar y a partir de ahi los parámetros son pasados directamente al evento.

La clase con su código fuente y ejemplos puede ser descargada desde aqui.


NOTA IMPORTANTE
Mucha de la funcionalidad proporcionada por esta clase, sobre todo usando la figura de controllers, puede ser implementada de forma nativa en VFP a partir de la introducción del comando BINDEVENTS.  La ventaja que da esta clase es que la misma es compatible con cualquier versión de VFP (solo usando eventos manejados por controller; los eventos con código dinámico requieren de VFP 7 o superior).

sábado, febrero 04, 2012

VFP: Un parser para JSON


Para los que, como yo, nunca hayan escuchado hablar de JSON, se trata de una tecnologia ampliamente usada en la web para el intercambio de datos entre sistemas desconectados. Básicamente es lenguaje muy simple que permite definir objetos y su contenido. Los parsers JSON hacen dos cosas:

a) Toman una referencia a un objeto (normalmente JavaScript) y genera una representación JSON en forma de string
b) Toman un string JSON y devuelve el objeto original

A pesar que en el sitio JSON.org se pueden encontrar dos parsers JSON para VFP, decidi hacer mi propio parser usando solo código VFP y, de paso, incluyendo un par de mejoras al estilo fox.

La mejor de estas adiciones es lo que llame "schema". Un schema es basicamente una forma de definir uns estructura de datos reutilizable, al estilo de la construcción STRUCT en C# (pero sin la posibilidad de incluir metodos).

Por ejemplo, para definir el schema "User":

JSON.declareSchema("User","{loginName:string, fullName: string, profileId: numeric, active: boolean}")

Luego, cuando queremos trabajar con un objeto que represente un usuario, solo hacemos:

oUser = JSONObject("schema:User")
oUser.loginName = 'vespina'
oUser.fullName = 'Victor Espina'
oUser.profileId = 25
oUser.active = .T.


Supongamos ahora que queremos almacenar los datos del usuario que modifico un registro. Con JSON podriamos hacerlo asi:

SELECT clientes
REPLACE rowLastUpd WITH DATETIME(),;
        rowUpdBy   WITH oUser.ToJSON()

Luego, cuando queramos mostrar quien modifico el registro, hacemos:

oUser = JSONObject(clientes.rowUpdBy)
MESSAGEBOX("Este registro fue modificado por " + oUser.fullName)


Otro uso muy comun de JSON es crear objetos sobre la marcha de forma sencilla:

oPoint = JSONObject("{x:10, y:20}")
?oPoint.x --> 10


Como ven, las posibilidades son muchas. En la documentacion de la libreria hay multitud de ejemplos de todo lo que se puede hacer con ella.


Descargar qdfoxJSON (version 1.2 del 9 Feb de 2012).