Abril 2008
L M X J V S D
« Mar   May »
 123456
78910111213
14151617181920
21222324252627
282930  

Generación de código con DSL Tools

Una de las posibilidades más interesantes de DSL Tools para Visual Studio es la generación de artefactos y código a partir del elementos pertenecientes al modelo de dominio que definamos para nuestro DSL. En el ejemplo de hoy usaremos el proyecto más básico de cuantos ofrece Visual Studio DSL Tools para obtener un generador de código básico que permitirá, definir un "lenguaje de programación visual" para nuestros usuarios. Obviamente, el alcance de la programación será algo limitado, máxime si tenemos en cuenta que se trata de un mero ejemplo de generación de código, pero nos permitirá vislumbrar hasta qué punto es potente y flexible esta herramienta.

En primer lugar, entramos a Visual Studio y creamos un nuevo proyecto Domain-Specific Languaje Designer, dentro de las plantillas Extensibility. Daremos un nombre a la solución, por ejemplo, MyDSLGenerator, y al pulsar en OK aparecerá un asistente para definir algunos de los parámetros de nuestro DSL. Seleccionaremos la plantilla MinimalTemplate, la extensión que tendrán los archivos de nuestro lenguaje (.mydlsg, en este ejemplo), y otras características como el espacio de nombres raíz para los proyectos de la solución. Hecho esto, pulsaremos en Finalizar, y tendremos ante nosotros el diseñador del DSL. Lo primero que nos preguntará siempre (a menos que indiquemos que no deseamos ser advertidos de ello) es que va a procederse a regenerar todos los archivos de la solución a partir de los Text Templates (archivos .tt) de la misma. Aceptamos, y nos encontraremos con algo similar a lo siguiente:

dsl1.PNG

Aunque podemos personalizar todo el DSL desde el proyecto Dsl de la solución, optaremos en esta entrada introductoria por hacer los mínimos cambios posibles. En primer lugar, hemos renombrado el nombre de los elementos del diagrama (ExampleShape, ExampleConnector, etc.).

dsl2.PNG

Lo más importante aquí va a ser definir una nueva propiedad de dominio sobre la clase xxElement (en nuestro caso, ActivityElement), ya creada por la propia plantilla del DSL. A esta propiedad podremos darle un valor, posteriormente, para cada Shape correspondiente a la clase que dibujemos en nuestro diseñador, o lo que es lo mismo, para cada objeto instanciado de la clase. Introduciremos una actividad denominada "Activity", de tipo string.

dsl21.PNG

Dentro del DSL Explorer haremos lo propio con las opciones correspondientes al Editor (Editor->Toolbox Tabs-> ActivitiesDesigner->Tools), para que aparezcan también los nombres en el Visual Studio Hive, y en la aplicación DSL una vez que la instalemos en otro equipo.

dsl3.PNG

Volvemos a generar el código del proyecto, pulsando sobre el botón Transform All Templates, y ejecutamos (F5). Aparecerá el Visual Studio Hive.

Creamos un diagrama acorde con lo especificado en nuestro DSL. Por ahora, lo único que hará es asignar una serie de propiedades a los Shapes (los rectángulos correspondientes a nuestras actividades). Estas propiedades son las que definimos anteriormente en el diseñador del DSL. Por un lado, la propiedad Name, que ya venía definida con la propia clase, y la propiedad Activity, que incluimos en ese momento.

dsl5.PNG

Para cada Shape, damos valor a las propiedades Name y Activity.

dsl6.PNG

Ahora vamos a preparar nuestro generador de código. Se tratará de un TextTemplate, de modo que añadimos un nuevo elemento al proyecto, de tipo fichero de texto, con el nombre LibraryCode.tt, y que va a permitir la generación de código a partir de los elementos existentes en nuestros diagramas. Más adelante nos quedará ver cómo llevar a cabo esta acción automáticamente cada vez que añadamos un elemento de nuestro lenguaje (archivo con extensión .mydlsg, que es la que definimos con este fin). De momento, lo generamos a mano, y le damos contenido.


<# /* ************************************************************* */ #>
<#@ template language="C#v3.5" inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" debug="true"#>
<#@ ActivitiesDesigner processor="ActivitiesDesignerDirectiveProcessor" requires="fileName='Sample1.mydlsg" #>
<#@ import namespace="System.Diagnostics" #>
<#@ output extension=".cs" #>
<# /* ************************************************************* */ #>
using System;
using System.Collections.Generic;
using System.Text;
using LOBOSOFT.MyDSLGenerator;

namespace LOBOSOFT.Activity
{

<# /* Creating main class*/ #>
///
/// The MainClass is the enter point for the functionality of this assembly
///

public class MainClass
{
public void MainMethod()
{
<# /* Calls to the private classes */
foreach(ActivityElement activity in this.ActivitiesModel.Elements){ #>
// Sequential caller
<#= activity.Name#>Class o<#= activity.Name#>Class = new <#= activity.Name#>Class();
o<#= activity.Name#>Class.m<#= activity.Name#>();

<#}#>
}
}

<# /* Creating classes for the Diagram Activities */
foreach(ActivityElement activity in this.ActivitiesModel.Elements)
{
#>
///
/// The <#= activity.Name#>Class gives functionality for <#= activity.Name#> managed class (test case)
///

public class <#= activity.Name#>Class
{
public void m<#= activity.Name#>()
{
<#= activity.Name#> o<#= activity.Name#> = new <#= activity.Name#>();
o<#= activity.Name#>.MainMethod();
}
}
<#
}
#>

}

A grandes rasgos, este código se encarga de recorrer los elementos de nuestro diagrama, generando código según los valores que hemos definido para las propiedades. En primer lugar, se encuentran una serie de directivas.

<#@ template language="C#v3.5"..., por ejemplo, indica el lenguaje usado para la plantilla, ya que después de generar el código, será validado sintácticamente según las reglas del lenguaje, y compilado en una DLL cuando compilemos nuestro proyecto. El v3.5 es opcional, y sería necesario para aplicaciones que usen C# del .NET Framework 3.5 (como por ejemplo, que hagan uso de LINQ).
<#@ ActivitiesDesigner processor="ActivitiesDesignerDirectiveProcessor" requires="fileName='Sample1.mydlsg"#> indica que haremos uso del archivo .mydslsg llamado Sample1. Por tanto, cada TextTemplate (.tt) irá vinculado inicialmente a un .mydslg, aunque veremos más adelante que esto podrá automatizarse.

El resto del template "escribe" el código en C# que necesitamos. Si pulsamos con el botón derecho del ratón sobre el archivo y seleccionamos la opción Run Custom Tool, o bien pulsamos sobre el botón Transform All Templates se generará el código C# asociado. En nuestro caso, el código correspondiente es el siguiente:

C#:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using LOBOSOFT.ManagedDLLEncapsulation;
  5.  
  6. namespace LOBOSOFT.Activity
  7. {
  8.  
  9. ///<sumary>
  10. /// The MainClass is the enter point for the functionality of this assembly
  11. ///</sumary>
  12. public class MainClass
  13. {
  14. public void MainMethod()
  15. {
  16. // Sequential caller
  17. pruebaClass opruebaClass = new pruebaClass();
  18. opruebaClass.mprueba();
  19.  
  20. }
  21. }
  22.  
  23. ///<sumary>
  24. /// The pruebaClass gives functionality for prueba managed class (test case)
  25. ///</sumary>
  26. public class pruebaClass
  27. {
  28. public void mprueba()
  29. {
  30. prueba oprueba = new prueba();
  31. oprueba.MainMethod();
  32. }
  33. }
  34.  
  35. }

El código será generado e incluso compilado si hemos incluido en las referencias del proyecto las DLLs que estamos usando.

Nos quedará por ver cómo automatizar varios de estos procesos, y cómo realizar el despliegue en otro ordenador de este DSL gráfico, pero eso será en una próxima entrega.


Entradas relacionadas:
  • Despliegue de nuestro propio DSL
  • Ironías de la vida
  • Lenguajes Específicos de Dominio en Visual Studio
  • Expresiones lambda vs Delegados y métodos anónimos
  • Expresiones Lambda en C#
  • Etiquetas: , ,

    Open Proj, la alternativa libre a Microsoft Project

    A la hora de planificar un proyecto de desarrollo software que implique el trabajo de varios desarrolladores y diversas tareas a acometer, la herramienta idónea para ello era Microsoft Project. Sin embargo, y aunque el potencial de la herramienta es muy alto, posiblemente como ocurre con tantas otras, no llegamos a aprovechar ni el 50% de sus posibilidades en el día a día, lo que no justifica el importante gasto en licencias que supone adquirir una o más copias de la herramienta. Además, nos encontramos con una aplicación propietaria, de código cerrado, de la que no es posible saber qué hace entre bambalinas, ni personalizarla en modo alguno. Por si esto fuera poco, sólo funciona en sistemas Windows. Ante esto, si la magnitud de los proyectos que vamos a llevar a cabo no justifica la adquisición de una o más licencias de Microsoft Project, no deseamos usar software privativo o, simplemente, queremos buscar una alternativa a la aplicación de Microsoft, tenemos algunas opciones interesantes dentro del mundo del software libre.

    openproj-big-small.jpg

    Una de las más interesantes es Open Proj, una aplicación open source que puede utilizarse en Linux, Unix, Mac o Windows, y que además accepta ficheros en el formato Project de Microsoft. Aunque no ofrece el 100% de la funcionalidad de su hermano privativo, lo cierto es que ese 40% real que usamos del mismo viene soportado con creces en esta aplicación multiplataforma. La probé hace algún tiempo, y ahora que la estoy usando por propia iniciativa en proyectos profesionales he de admitir que no tiene nada que envidiar a la aplicación de Microsoft. Una interfaz gráfica de similares características (eso sí, algo menos fluida, debido a que usa JRE para su ejecución y los WinForms suelen ser más eficientes en entornos Windows), y similares opciones a la hora de gestionar nuestros proyectos. Recomendable, sin duda alguna.


    Entradas relacionadas:
  • La perfidia del software
  • Editores de código fuente
  • ¿Cómo saber si Google ha pasado a indexar nuestra web?
  • Un manual de referencia Python en Firefox
  • Editando los recursos de un binario
  • Etiquetas: ,