Angel "Java" Lopez

NET, Java, PHP y Desarrollo de Software

This Blog

Syndication

Search

Tags

Community

Email Notifications

Archives

.NET

ASP.NET

Windows Form

VB.NET

C#

Sitios

Blogs

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

Published Sat, Jun 27 2009 7:59 by lopez

Leave a Comment

(required) 
(required) 
(optional)
(required) 
If you can't read this number refresh your screen
Enter the numbers above: