Nota del autor

Si la entrada que estás leyendo carece de imágenes, no se ve el vídeo que teóricamente lleva incrustado o el código fuente mostrado aparece sin formato, podéis conocer los motivos aquí. Poco a poco iré restableciendo la normalidad en el blog.
Este blog es un archivo de los artículos situados previamente en Lobosoft.es y ha dejado de ser actualizado. Las nuevas entradas pueden encontrarse en www.lobosoft.es. Un saludo,
Lobosoft.
Mostrando entradas con la etiqueta DSL. Mostrar todas las entradas
Mostrando entradas con la etiqueta DSL. Mostrar todas las entradas

martes, 6 de mayo de 2008

Despliegue de nuestro propio DSL

Hace unos días veíamos cómo crear una herramienta personalizada mediante el uso de las DSL Tools que proporciona el SDK de Visual Studio 2008. Si bien podemos desarrollar y probar nuestro DSL que a tal efecto proporciona el Experimental Hive de Visual Studio, lo cierto es que una vez desarrollado el producto, e incluso durante el proceso de desarrollo, podemos desear comprobar cómo funciona el mismo en un entorno de pre-producción. Para ello, debemos generar un proyecto de despliegue (un setup) para el proyecto DSL, y aunque no es un proceso precisamente trivial, ya que implica la vinculación de extensiones de archivos a nuestro editor DSL mediante la modificación del Registro de Windows, y la instalación de determinados archivos en ubicaciones muy específicas, lo cierto es que el propio Visual Studio proporciona un tipo de proyecto que puede facilitarnos la tarea.


En principio, como avanzamos, realizar un proyecto de instalación de un DSL no es algo sencillo, a pesar de lo que pueda parecernos inicialmente cuando empezamos a trabajar con ellos, ya que estamos hablando de la instalación de un Visual Studio Package. Para obtener el mejor rendimiento y aprovechar al máximo la capacidad del instalador deberíamos hacernos con WiX (Windows Instaler XML), un potente entorno de despliegue basado en XML, y distribuido libre de licencia por Microsoft. Existe un excelente tutorial de WiX en Internet, además de lo que podemos leer en la página oficial del producto, y también podemos usar herramientas comerciales como la Software Factories Toolkit, que al fin y al cabo está basada en WiX.


En cualquier caso, y de momento, vamos a basarnos en el proyecto de instalación para DSLs que incorpora Visual Studio, y que también se basa en WiX para crear un entorno sencillo aunque en principio limitado para la instalación de nuestros productos.


En principio, para la instalación de un diseñador DSL necesitaremos los archivos siguientes:




  • .msi del diseñador.

  • .msi del DSL Tools Redistributable, ya que si el equipo destino de la instalación no tiene instaladas las DSL Tools (a partir del SDK de Visual Studio) el diseñador no funcionaría. También es posible que necesitemos registrar una Package Load Key (PLK). En la página de VS Extensibility de Microsoft se puede encontrar más información sobre este proceso. En cualquier caso, la PLK se aplicará sobre la clase package (Shell\Package.tt), mediante el atributo VSShell::ProvideLoadKey(keynumber)]. La PLK se almacenará en el fichero de recursos VSPackage.resx.

  • setup.exe, encargado de instalar en el orden adecuado, y si son necesarios, los distintos .msi.

  • settings.ini, con la configuración necesaria para el setup.exe.

  • Archivos adicionales, como el Readme o la licencia del producto.


 


dslsetup01.PNG


Así pues, comenzaremos el trabajo de generación del instalador abriendo nuestra solución DSL (compuesta por los proyectos DSL y DSL Package), y agregando un nuevo proyecto de tipo DSL Setup. El proyecto se compone básicamente de una serie de archivos, cuya finalidad es la siguiente:

  • .dslsetup: información sobre los componentes del DSL. A partir de la misma los text templates (.tt) generarán los archivos necesarios para la compilación de WiX. En este archivo se añadirán todos los recursos necesarios para la instalación y funcionamiento del DSL (.TT's, .DLL's, etc.).

  • settins.ini: información para setup.exe. Identifica el .msi del producto, incluyendo su nombre. Sólo debe modificarse si el nombre del producto sufre algún cambio.

  • Strings.wxl: UI del wizard de instalación. Permite cambiar los lenguajes, localización, etc.

  • Product.ico: El icono del producto. Será el que Windows muestre en el Panel de Control, dentro de Añadir y Quitar Programas.


Si realizamos cualquier cambio en la definición del diseñador DSL deberemos seguir los siguientes pasos:




  1. Rebuild de los proyectos DSL y DSL Package.

  2. Regenerar los ficheros para WiX a partir de los Text Templates.

  3. Rebuild del proyecto DSL Setup.


Además de esto, para disponer del proyecto DSL en nuestro instalador deberemos hacer lo siguiente:




  1. Ejecutar el proyecto DSL para abrir el Visual Studio Experimental Hive. Una vez dentro, limpiaremos el proyecto DSL para dejarlo tal y como nos gustaría que quedase un nuevo proyecto basado en el mismo (únicamente los archivos .tt necesarios y algún fichero del modelo recién creado, por ejemplo Sample1.mydsl), y hacer un Clean Up del proyecto.

  2. Seleccionamos el proyecto en la solución.

  3. Dentro del menú Archivo (File) de Visual Studio Experimental Hive, seleccionamos la opción de Exportar Plantilla (Export Template).
    dslsetup02.PNG

  4. Copiar la plantilla de proyecto recién creada en el proyecto Setup. Podemos darle el nombre: Nombreproyecto.Code.tt).

  5. Añadir a .dslsetup la línea:




  6. Ejecutar (run) todos los Text Templates de la solución DSL para regenerar los archivos de WiX.


Tras compilar toda la solución, tendremos un instalador para nuestro DSL.

 


dslsetup03.PNG


Si lo instalamos en un equipo nuevo, podremos crear un nuevo proyecto correspondiente a nuestro DSL simplemente entrando en Visual Studio, indicando que deseamos crear un nuevo proyecto y seleccionando la plantilla de entre las que tenemos disponibles en la sección "Mis Plantillas".



dslsetup04.PNG


Aquí vemos cómo quedaría un proyecto de este tipo. Tendríamos, para el proyecto, las herramientas que diseñamos en el DSL, asociadas a sus Shapes correspondientes:


 


dslsetup05.PNG


También vemos la estructura del proyecto, idéntica a la que exportamos del Experimental Hive.


dslsetup06.PNG


Y un programa diseñado en este lenguaje podría quedar así:


 


dslsetup07.PNG


Por último, basta con ejecutar nuevamente el setup, y seleccionar la opción de eliminar el producto de nuestro equipo, si deseamos dejarlo tal y como l teníamos originariamente.

martes, 29 de abril de 2008

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.








using System;
using System.Collections.Generic;
using System.Text;
using LOBOSOFT.MyDSLGenerator;

namespace LOBOSOFT.Activity
{


///
/// 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
Class oClass = new Class();
oClass.m();


}
}

<# /* Creating classes for the Diagram Activities */
foreach(ActivityElement activity in this.ActivitiesModel.Elements)
{
#>
///
/// The Class gives functionality for managed class (test case)
///
public class Class
{
public void m()
{
o = new ();
o.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).
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:


[csharp]
using System;
using System.Collections.Generic;
using System.Text;
using LOBOSOFT.ManagedDLLEncapsulation;

namespace LOBOSOFT.Activity
{

///
/// The MainClass is the enter point for the functionality of this assembly
///
public class MainClass
{
public void MainMethod()
{
// Sequential caller
pruebaClass opruebaClass = new pruebaClass();
opruebaClass.mprueba();

}
}

///
/// The pruebaClass gives functionality for prueba managed class (test case)
///
public class pruebaClass
{
public void mprueba()
{
prueba oprueba = new prueba();
oprueba.MainMethod();
}
}

}
[/csharp]

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.

sábado, 12 de abril de 2008

Lenguajes Específicos de Dominio en Visual Studio

"Lenguaje personalizado que se centra en un dominio problemático y define el problema en un nivel alto de abstracción", es la descripción que proporciona Microsoft en su glosario de Visual Studio Team System para los DSL, o Lenguajes Específicos de Dominio, a los que da soporte, entre otros, mediante el Visual Studio SDK, en el que centraremos la entrada de hoy.


Los lenguajes específicos de dominio han venido utilizándose desde los albores de la informática. Como su propia definición indica, estos lenguajes enfocan el problema desde alto nivel, abstrayendo al programador de los detalles de la implementación. Imaginemos que deseamos realizar una consulta sobre una base de datos, o un fichero XML. Con un lenguaje de propósito general generalmente utilizaríamos alguna API o capa de acceso a datos que nos abstrajese de los detalles. Los lenguajes de dominio específico "son" la propia abstracción en sí, y permiten solicitar qué queremos, sin necesidad de hacer lo propio con el cómo lo queremos obtener. Así, los DSLs son lenguajes declarativos, y tenemos ejemplos de ellos en el SQL, XQuery o el propio LINQ.


Como avanzaba al comienzo, Visual Studio 2008 SDK (existen también versiones previas del producto para ediciones más antiguas de VS) proporciona diversas herramientas que posibilitan la extensibilidad del IDE (no en vano se encuentra dentro de la gama de productos Visual Studio Extensibility), dotándole de capacidades específicas para la resolución de problemas como el que nos ocupa. Al SDK se le complementaría, por ejemplo, con Visual Studio 2008 Shell, que ya introdujimos hace un tiempo, y en el que profundizaremos dentro de no mucho tiempo.


dsl-sdk.PNG


Si descargamos el SDK (actualmente en su versión 1.0) de la página de Microsoft y procedemos a instalarlo, veremos que nos proporciona una serie de recursos para trabajar con DSLs, WCF, creación de Add-ins y extensiones específicas para el tratamiento de datos. Nos centraremos hoy en el primero de ellos, viendo además la interesante posibilidad de producir DSL "gráficos" mediante los cuales podamos proporcionar a los usuarios elementos de programación rudimentarios pero a la vez potentes. Por ejemplo, podríamos crear un DSL que constase de componentes mecánicos e interconexiones para fabricar maquinaria pesada, y que el propio Visual Studio verificase en la "compilación" del lenguaje que se cumplen todas las restricciones necesarias para que el programa diseñado (un camión, por ejemplo) sea correcto. La salida de la compilación podría ser desde especificaciones en XML, a un ejecutable con determinada funcionalidad. El abanico que se abre ante nosotros es amplio y apasionante, como veremos.


Hoy simplemente nos centraremos en uno de los ejemplos que proporciona el SDK, y en una próxima entrada veremos cómo generar uno propio. Abrimos el ejemplo del árbol genealógico (Family Tree DSL), diseñado específicamente para mostrarnos cómo funcionan los validadores, sirviéndonos además de introducción a los lenguajes de diseño gráficos que generan, como decíamos, código para los componentes o "artefactos" que dibujemos.


DSL Tree Family Sample - Visual Studio 2008 SDK


Una vez cargado el proyecto, procedemos a ejecutarlo y... voilà, tenemos otro Visual Studio como resultado de la ejecución. Pero no es el mismo Visual Studio, sino uno preparado para dar soporte al DSL creado en el ejemplo. Veremos que disponemos de artefactos persona, que podemos arrastrar al diseñador, e interconexiones de parentesco (enlaces matrimoniales y relaciones padre-hijo), así como diversos atributos, como el año de nacimiento y de defunción de las personas.


DSL Tree Family Sample - Visual Studio 2008 SDK


Si probamos a ejecutar el proyecto, obtendremos un error de validación que nos indica que un hijo no puede nacer después de la fecha de nacimiento del padre.


DSL Tree Family Sample - Visual Studio 2008 SDK


Tampoco podrá hacerlo, si probamos a cambiarlo, antes del nacimiento de éste. Por último, si corregimos las fechas y volvemos a ejecutar, el proyecto "compilará" correctamente, produciendo en su caso una salida adecuada.


DSL Tree Family Sample - Visual Studio 2008 SDK


Otro de los ejemplos que proporciona Visual Studio 2008 SDK es un diseñador de diagramas de clases en UML bastante curioso, por cierto. En una próxima entrada veremos cómo diseñar nuestro propio DSL, incluyendo validadores y una salida a la compilación de los proyectos.