Transformando plantillas en AjGenesis

AjGenesis se base en modelo libre, y usa plantillas (templates) para facilitar la descripción y generación de un archivo de texto final. La forma más simple de transformar un archivo de plantilla en un archivo destino es con un comando como:

AjGenesis.Console Model.xml ModuleVb.tpl HelloWorld.vb

Donde Model.xml puede tener

<Project Company="ajlopez.com">


<Message>Hola, Mundo</Message>


<Author>Pepe</Author>


</Project>

ModuleVb.tpl es la plantilla:

'


' Automatically generated by AjGenesis


' http://www.ajlopez.com/ajgenesis


' Company ${Project.Company}


'


 


Module Module1


 


    Sub Main()


        System.Console.WriteLine("${Project.Message}")


    End Sub


 


End Module

Produciendo HelloWorld.vb

'


' Automatically generated by AjGenesis


' http://www.ajlopez.com/ajgenesis


' Company ajlopez.com


'


 


Module Module1


 


    Sub Main()


        System.Console.WriteLine("Hola, Mundo")


    End Sub


 


End Module

(Los ejemplos de HelloWorld que describo los pueden encontrar en la versión liberada 0.5, dentro del directorio examples, hay varios directorios HelloWorld*) (Más detalle en Generando Código- Hello World con AjGenesis)

La otra opción es desde una tarea, programáticamente:

AjGenesis.Console Model.xml Build.ajg

donde Build.ajg es un archivo de tareas, escrito en AjGenesis:

PrintLine "Generating HelloWorld"


 


TransformerManager.Transform("ModuleVb.tpl", "HelloWorld.vb", Environment)


 


 

El objeto TransformerManager es un objeto auxiliar, de los que están ya definidos en AjGenesis, para que podamos aprovecharlo. Su “gran método” es .Transform que toma:

- Nombre del archivo de plantilla
- Nombre del archivo a generar
- El Environment

Environment es otro objeto predefinido, que es un diccionario donde están definidos los nombres y valores de variables en curso. Tanto “TransformerManager” como “Environment” son claves/keys dentro de ese directorio. Cuando uno escribe en AjBasic:

a = 1

agrega automáticamente la entrada “a” y el valor 1 en el Environment.

Es común que la transformación de plantillas se escriba en tareas más complejas. Fragmento de un ejemplo (ver examples/HelloWorldNet20/Tasks/Build.ajg):

PrintLine "Creating Solution File"


 


TransformerManager.Transform("Templates\Solution.tpl", "${Project.BuildDir}\${Project.Name}\${Project.Name}.sln", Environment)


 


PrintLine "Creating VB.Net Project"


 


TransformerManager.Transform("Templates\ModuleVb.tpl", "${Project.BuildDir}\${Project.Name}\${Project.Name}Vb\Module1.vb", Environment)


TransformerManager.Transform("Templates\AssemblyInfoVb.tpl", "${Project.BuildDir}\${Project.Name}\${Project.Name}Vb\My Project\AssemblyInfo.vb", Environment)


TransformerManager.Transform("Templates\VbProject.tpl", "${Project.BuildDir}\${Project.Name}\${Project.Name}Vb\${Project.Name}Vb.vbproj", Environment)


'TransformerManager.Transform("Templates\VbProjectUser.tpl", "${Project.BuildDir}\${Project.Name}\${Project.Name}Vb\${Project.Name}Vb.vbproj.user", Environment)


 


PrintLine "Creating C# Project"


 


TransformerManager.Transform("Templates\ClassCs.tpl", "${Project.BuildDir}\${Project.Name}\${Project.Name}Cs\Program.cs", Environment)


TransformerManager.Transform("Templates\AssemblyInfoCs.tpl", "${Project.BuildDir}\${Project.Name}\${Project.Name}Cs\Properties\AssemblyInfo.cs", Environment)


TransformerManager.Transform("Templates\CsProject.tpl", "${Project.BuildDir}\${Project.Name}\${Project.Name}Cs\${Project.Name}Cs.csproj", Environment)


'TransformerManager.Transform("Templates\CsProjectUser.tpl", "${Project.BuildDir}\${Project.Name}\${Project.Name}Cs\${Project.Name}Cs.csproj.user", Environment)

Un problema que encontré, es que si regeneramos desde el modelo todos estos archivos finales, los pisamos, los creamos de nuevo. Supongamos que sólo queremos generar el archivo destino, si no existe de antes (una táctica destinada a preservar el archivo destino, por si lo hemos modificado nosotros). En un proyecto (el proyecto Medusa que mencionó en Generando y regenerando texto y código con AjGenesis, Generación de código con AjGenesis para Mere Mortals Framework), usamos esta rutina, que definimos en AjBasic:

sub TransformNewFile(tpl, target, tm, env)


    if System.IO.File.Exists(target) then


        return


    else


        tm.Transform(tpl, target, env)


    end if


end sub

Que invocamos, por ejemplo, con:

TransformNewFile("Templates\ClassPartialVb.tpl", ".\${Project.Name}BO\${Project.Name}BO\${Table.Name}\${Table.Name}.Partial.vb",TransformerManager, Environment)

Pero nos ha resultado muy útil, tener otra rutina, que reemplaza el archivo destino, pero si éste existe, solamente lo reemplaza si su contenido actual es distinto del contenido nuevo que vamos a generar:

 


sub TransformFile(tpl, target, tm, env)


    if System.IO.File.Exists(target) then


        target2 = target & ".tmp"


        tm.Transform(tpl, target2, env)


        content1 = System.IO.File.ReadAllText(target)


        content2 = System.IO.File.ReadAllText(target2)


        if content1 <> content2 then


            System.IO.File.Copy(target2, target, true)


        end if


        System.IO.File.Delete(target2)


    else


        tm.Transform(tpl, target, env)


    end if


end sub

Se puede mejorar (usar un stream en memoria, en lugar de un archivo temporal). Un ejemplo de uso:

TransformFile("Templates\DefaultAspx.tpl", ".\${Project.Name}Web\Default.aspx",TransformerManager, Environment)


TransformFile("Templates\DefaultAspxVb.tpl", ".\${Project.Name}Web\Default.aspx.vb",TransformerManager, Environment)


TransformFile("Templates\GlobalAsax.tpl", ".\${Project.Name}Web\Global.asax",TransformerManager, Environment)


TransformFile("Templates\MasterPageMainMaster.tpl", ".\${Project.Name}Web\MasterPageMain.master",TransformerManager, Environment)


TransformFile("Templates\MasterPageMainMasterVb.tpl", ".\${Project.Name}Web\MasterPageMain.master.vb",TransformerManager, Environment)


TransformFile("Templates\UserLoginAspx.tpl", ".\${Project.Name}Web\UserLogin.aspx",TransformerManager, Environment)


TransformFile("Templates\UserLoginAspxVb.tpl", ".\${Project.Name}Web\UserLogin.aspx.vb",TransformerManager, Environment)


TransformFile("Templates\WebConfig.tpl", ".\${Project.Name}Web\web.config",TransformerManager, Environment)

La rutina TransformFile nos ha resultado muy útil, al usar un sistema de repositorio de código. Cuando cambiamos el modelo, y regeneramos todo lo que determinamos que se genera (contrapuesto a lo que tenemos como archivos manuales en nuestra solución), ahora, cuando vamos a guardar en el repositorio de código, los archivos que no cambiaron su contenido (ni su fecha y hora de grabación) son los que se envían al servidor. Esto ha simplificado todos los commits, y hasta sirve para darse cuenta cuál es el efecto de un cambio en el modelo inicial: el propio software de repositorio de código nos avisa qué archivos quedaron cambiados.

Esas dos rutinas las pusimos en un archivo Templates\Utilities.tpl y las incluimos en nuestras tareas con:

include "Templates/Utilities.tpl"



Seguramente, comenzaran a aparecer en los ejemplos que vaya publicando.



Nos leemos!



Angel “Java” Lopez
http://www.ajlopez.com/
http://twitter.com/ajlopez
http://www.facebook.com/ajlopez

This entry was posted in 2643, 6145. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>