Generando con AjGenesis desde los assemblies
AjGenesis es una herramienta de generación de código a partir de templates y un modelo libre.
Bien vayamos a esta frase, se dice rápido… pero analicemosla: "…a partir de templates…", esto no tiene nada de nuevo, MyGeneration lo hace, y millones de generadores de código que andan sueltos por ahí también. Pero el punto más que interesante está: "a partir de un modelo libre", y esto que quiere decir ? Significa que no hay restricciones sobre como debe ser el modelo. Si bien debe ser escrito en Xml, esta es una forma de representar el modelo para que lo analice AjGenesis, esto no puede ser considerado una restricción.
Ahora bien, el modelo de AjGenesis puede ser generado inclusive desde la base de Datos, existen unos ejemplos de ello disponible junto con la distribución de AjGenesis.
Hace un tiempo salió la inquietud de que AjG podría generar el modelo a partir de los hbm de NHibernate, la gente que usa NHibernate estaría contenta incluyendome. Pero estuve pensando que los xml se deberían sobrecargar con muchos datos que por ahora los defaults de NHibernate los consideran dejando el mapping más limpio y fácil de leer. Por ejemplo, mis mappings files no tienen el tipo de dato (salvo excepciones), NHibernate hace el trabajo, sin esta información, el modelo que se genere ó el código que se genere junto a los templates es casi inutil sin los tipos de datos.
Otra opción para generar el modelo, es a partir de las clases disponibles en los ensamblados de la aplicación que estemos usando. Hace un tiempo escribà esta herramienta que ahora decidí cambiarla un poco. Ahora escribí ésta herramienta que la pueden descargar aquí.
Como funciona AjGenesis.FromAssembly? Facil, es una librería que itera sobre un ensamblado especificado y devuelve una lista de Objetos que representan la estructura de las clases:
<# AjGenesisFromAssemblyPath = "..\..\bin\AjGenesis.FromAssembly.dll" function GetEntities(path) AssemblyManager.LoadFrom(AjGenesisFromAssemblyPath) obj = new AjGenesis.FromAssembly.Collector() list = obj.GetEntities(path,null) return list end function
AssemblyManager es la clase encargada de cargar el assembly, una vez hecho esto podemos trabajar con él.
Para obtener la listar las clases en el assembly usamos la clase Collector, y la función GetEntities, especificando la ruta del ensamblado.
El template para generar la configuración de IoC en el xml, podrÃa ser similar a este:
<#
nsServices = "MyApp.Service"
assemblyName = "MyApp.Service"
moneySign = "$"
oBraces = "{"
cBraces = "}"
include "${TemplateDir}\Functions.tpl"
#>
<#
for each Entity in Entities
#>
<${Entity.Name}Dao>${moneySign}${oBraces}${Entity.Name}.Dao${cBraces}
${Entity.Name}Dao>
<#
end for
#>
Algo interesante al generar código que a su vez tiene instrucciones de un lenguaje “tipo” template, es decir con comandos de esta forma ${variable}, es que debemos usar caracteres en el código generado y en el codigo para que lo interprete el generador de código. AjGenesis en los templates y Windsor en la configuración, usan los caracteres $, {, }. De modo que para no que AjGenesis no se confunda en el parseo, creé variables que contienen estos sÃmbolos.
Existen muchas cosas que se me ocurrieron para mejorarlo, pero la base ya está, ahora hay que empezar a retocarla. Se me planteó la inquietud crear atributos (annotations) para las clases de modo que se pueda enriquecer o restringir el modelo generado. Pero supongo que serÃa la primera herramienta de generación de código intrusiva que se pueda configurar por medio de annotaciones y quizas se convertirÃa en overhead para la aplicación.