Documentando el Código con MonoDoc y Monodevelop
Trabajando con Monodevelop
me llamó la atención
la ayuda que viene incluida, en la cual viene una gran cantidad de
información como la documentación de las
librerías de clase implementadas en mono, incluyendo la
escueta documentación de Gtk# en las librerías
de
Gnome. No tardé en descubrir que se trataba de una
implementación de MonoDoc
Viewer en Monodevelop.
Aunque existen varias formas de crear documentación para MonoDoc, en este artículo me centraré en la documentación directa del código fuente "inline" en MonoDevelop y después convertirla en un formato de lectura para MonoDoc.
Como siempre, primero creamos un proyecto en Monodevelop desde el menú "Archivo" en la opción "Nuevo Proyecto...", seleccionamos un "Proyecto Gtk# 2.0" y le asignamos un nombre. En este ejemplo le puse el nombre "Documentacion" y estoy usando la versión 0.13.1 de MonoDevelop.

MonoDevelop nos permite configurar ciertas características que en este proyecto en particular; será necesario ajustar la versión del runtime a utilizar y la generación de documentación XML.
Para este ejemplo estoy trabajando con una clase que usa el nombre de espacio "System.Collections" el cual solo esta disponible en la versión 2.0 del runtime. Para cambiar la versión del runtime a utilizar, solo debemos ir al menú "Proyecto" y seleccionar la opción "Opciones...", de esta forma saldrá una ventana donde buscaremos "General" -> "Opciones del Runtime", y seleccionamos la versión "2.0"

Para seleccionar la generación de documentación solo debemos ir a "Configuraciones" -> "Debug" -> "Generación de Código", y seleccionaremos la casilla "Generar Documentación XML".

Con esto, MonoDevelop generará un archivo XML que posteriormente utilizaremos y convertiremos al formato de MonoDoc.
La clase de ejemplo se llama NomadTPL, es una clase que manipula variables en una cadena de texto, y las reemplaza con otros valores, me es de mucha utilidad cuando trabajo con "querys" largos, donde quiero tener un mayor control de las variables que deberán ser usadas. Recuerden que yo vengo de trabajar con PHP donde es muy común trabajar con motores de templates como Smarty o phemplate.
Para poder crear la clase es necesario agregar un nueva clase vacía al proyecto, y se logra dando clic con el botón derecho del ratón sobre el nombre del proyecto en la ventana de la solución, buscamos la opción "Añadir" y luego "Nuevo Archivo...".

Saldrá una ventana donde seleccionaremos en "General" una "Clase Vacía" con el nombre de "NomadTPL"

El código de la clase es el siguiente:
using System; using System.Collections.Generic; using System.Text.RegularExpressions; namespace Documentacion { /// <summary> /// Descripcion de la clase /// </summary> public class NomadTPL { // Declaracion de Variables usadas en la clase private string TextSource; private string TextResult; private Unassigned UnassignedAction; private Dictionary<string, string> VarsCollection = new Dictionary<string, string>(); /// <summary> /// Contructor de la Clase con Parametros. /// </summary> /// <param name="Text">El texto que se procesara en busca de variables del tipo <c>{variable}</c></param> public NomadTPL(string Text) { this.TextSource = Text; this.UnassignedAction = Unassigned.Remove; } /// <summary> /// Contructor de la Clase con Parametros. /// </summary> /// <param name="Text">El texto que se procesara en busca de variables del tipo <c>{variable}</c></param> /// <param name="UnassignedVars">Accion a realizar sobre variables no remplazadas</param> public NomadTPL(string Text, Unassigned UnassignedVars) { this.TextSource = Text; this.UnassignedAction = UnassignedVars; } /// <summary> /// Enumerador de acciones de Variables sin asignaciones. /// </summary> public enum Unassigned { /// <summary>Elimina todas las variables no encoentradas</summary> Remove = 1, /// <summary>Mantiene las variables no encontradas</summary> Keep = 2, /// <summary>Marca todas las variables no encontradas</summary> Mark = 4 } /// <summary> /// Regresa o establece la accion a realizar sobre variables no remplazadas en tiempo de ejecucion. /// </summary> /// <returns>Un valor "Unassigned" de accion sobre las variables no remplazadas.</returns> public Unassigned SetUnassigned { get { return this.UnassignedAction; } set { this.UnassignedAction = value; } } /// <summary> /// Regresa o establece el texto a reemplazar. /// </summary> /// <returns>Un valor String con el texto a reemplazar.</returns> public string SourceText { get { return this.TextSource; } set { this.TextSource = value; } } /// <summary> /// Carga un nuevo texto a reemplazar y borra todas las variables preexistentes. /// </summary> /// <param name="text">El texto que se procesara en busca de variables del tipo <c>{variable}</c></param> public void LoadNew(string text) { this.TextSource = text; this.VarsCollection.Clear(); } /// <summary> /// Realiza los remplazos de variables en el texto proporcionado. /// </summary> /// <returns>El texto con variables reemplazadas</returns> public string Output() { this.TextResult = this.TextSource; this.Parse(); return this.TextResult.ToString(); } /// <summary> /// Agrega una variable para su posterior parseo. /// </summary> /// <param name="Variable">El nombre de la variable que se encuentra en el texto</param> /// <param name="Replace">El valor con el que se reemplazara la variable</param> public void AddVar(string Variable, string Replace) { if (!this.VarsCollection.ContainsKey(Variable)){ this.VarsCollection.Add(Variable, Replace); } } /// <summary> /// Realiza el Parseo de Variables y Valores. /// </summary> private void Parse() { foreach (KeyValuePair<string, string> myData in this.VarsCollection){ this.TextResult = Regex.Replace(this.TextResult.ToString(), "{(" + myData.Key.ToString() + ")}", myData.Value.ToString()); } if (UnassignedAction == Unassigned.Remove){ this.TextResult = Regex.Replace(this.TextResult, "{(\\w+)}", ""); } else if (UnassignedAction == Unassigned.Mark){ this.TextResult = Regex.Replace(this.TextResult, "{(\\w+)}", "MARK:($1)"); } } } }
Si revisamos el código anterior veremos que tiene comentarios que empiezan con "///", y dentro una estructura de "tags" tipo XML. Efectivamente es eso, XML basado en una especificación que podemos encontrar en la Recomendación de tags para la documentación en comentarios, también llamado "Inline XML Documentation"
Ya en este punto es posible generar la documentación XML, sin embargo el plan es crear una pequeña aplicación que muestre el funcionamiento de la clase, así que explicaré de forma muy general y sin detalles el funcionamiento de dicha aplicación.
Para el diseño del Formulario deberemos crear correctamente sus espacios usando los controles contenedores "Table" y "VBox" más o menos de la siguiente forma:

Usaremos seis "label", dos "entry", un "combobox", dos "textview" y un "hbuttonbox" con dos "button" ubicados de la siguiente forma:

Ok, para no perder el objetivo de este artículo hasta aquí terminamos con la aplicación, si deseas más información es posible descargar el proyecto al final de este documento.
Al momento de construir la solución, si revisamos el directorio del ensamblado nos podemos encontrar lo siguiente:
[nexus@Develop Documentacion]$ ls -alF Documentacion/bin/Debug/
total 44
drwxr-xr-x 2 nexus nexus 4096 2007-04-28 23:21 ./
drwxr-xr-x 3 nexus nexus 4096 2007-04-21 00:58 ../
-rwxr-xr-x 1 nexus nexus 24576 2007-04-28 23:15 Documentacion.exe*
-rw-r--r-- 1 nexus nexus 4629 2007-04-28 23:15 Documentacion.exe.mdb
-rw-r--r-- 1 nexus nexus 3470 2007-04-28 23:15 Documentacion.xml
Veremos que se generó un archivo llamado "
Documentacion.xml", con el cual vamos a
trabajar. Para ello usaremos
el comando "monodocer" que es la herramienta
de MonoDoc que prepara los
archivos de la documentación. Existen muchas opciones con
las que se puede trabajar, pero para el caso que nos interesa usaremos-prettyIdenta la estructura XML-importslashdoc:fileEl archivo XML a importar, producido por la opción "/doc" de mcs-assembly:fileEspecifica el ensamblado en el que se basa la documentación-path:directoryEn que directorio se generará el árbol de documentación
Ya dentro del directorio del ensamblado ejecutamos la siguiente linea:
[nexus@Develop Debug]$ monodocer -pretty -importslashdoc:Documentacion.xml -assembly:Documentacion.exe -path:Documentacion
Namespace Directory Created: Documentacion
New Type: Documentacion.NomadTPL
New Namespace File: Documentacion
New Type: Documentacion.NomadTPL+Unassigned
Members Added: 0, Members Deleted: 0
Lo anterior va a crear un nuevo directorio llamado "Documentacion" con la siguiente estructura:
.
|-- Documentacion
| |-- NomadTPL+Unassigned.xml
| `-- NomadTPL.xml
|-- Documentacion.xml
`-- index.xml
Hasta este momento aún no se encuentra completamente ensamblada nuestra documentación, de hecho solo son partes necesarias para realmente crear el ensamblado llamadas "Initial Stubs". Esto es debido a que aún estamos en posibilidades de seguir editando nuestra documentación haciendo uso del MonoDoc Viewer de forma muy fácil con el siguiente comando:
[nexus@Develop Debug]$ monodoc --edit Documentacion/
Esto abrirá el GUI de MonoDoc donde podemos explorar nuestra documentación en modo de edición.

El navegador de MonoDoc es muy fácil de usar y bastante práctico para darle los últimos detalles a la documentación generada, solo es necesario pulsar sobre los enlaces "[Edit]" y agregar o modificar la información para después pulsar sobre el botón "Save".

Ya terminado de darle los últimos detalles es hora de ensamblar la documentación y agregarla a nuestro árbol de MonoDoc para que se encuentre accesible en todo momento, para ellos usaremos otra herramienta llamada "mdassembler" de la siguiente forma:
[nexus@Develop Debug]$ mdassembler --ecma Documentacion/ -o Documentacion
Processing namespace Documentacion
Processing input file NomadTPL+Unassigned.xml
Processing input file NomadTPL.xml
Have 2 elements in the Documentacion
Lo anterior nos va a crear 2 archivos nuevos: "
Documentacion.tree"
y
"Documentacion.zip", debemos crear un tercer
archivo llamado
"Documentacion.source" con el siguiente
contenido:<?xml version="1.0"?>
<monodoc>
<source provider="ecma" basefile="Documentacion" path="Documentacion"/>
</monodoc>
Ya en este momento podemos agregar la documentación al árbol común de MonoDoc y lo podemos encontrar con alguno de los siguientes comandos:
pkg-config monodoc --variable=sourcesdir
monodoc --get-sourcesdir
En mi caso se encuentra en "
/usr/lib/monodoc/sources",
así
que es necesario copiar los 3 archivos para allá.Develop:Debug# cp Documentacion.{source,tree,zip} /usr/lib/monodoc/sources
Ya por último y para terminar necesitamos agregar el nodo de la documentación en el árbol de documentación. Para lograrlo solo necesitamos editar el archivo "
monodoc.xml" que en mi caso se
encuentra en
"/usr/lib/monodoc/" y agregar un
último nodo con la
información de nuestra documentación de la
siguiente forma:<?xml version="1.0"?>
<node label="Mono Documentation" name="root:">
<node label="Class Library" name="classlib"/>
<node label="Mono Libraries" name="classlib-mono"/>
<node label="Gnome Libraries" name="classlib-gnome"/>
<node label="Mozilla Libraries" name="classlib-gecko"/>
<node label="Novell Libraries" name="classlib-novell"/>
<node label="MonoDevelop IDE Libraries" name="monodevelop" />
<node label="C# Language Specification" name="ecmaspec" />
<node label="C# Compiler Error Reference" name="cs-errors" />
<node label="Mono Development Tools" name="dev-tools">
<node label="Mono Debugger" name="debugger"/>
</node>
<node label="Mono Embedding" name="embed"/>
<node label="Various" name="various">
<node label="DiaCanvas Libraries" name="classlib-diacanvas"/>
<node label="NUnit Libraries" name="classlib-nunit"/>
<node label="Tao" name="tao"/>
</node>
<node label="Proyectos" name="proyectos">
<node label="Documentacion" name="Documentacion"/>
</node>
</node>
Listo, en la siguiente ocasión que abramos MonoDoc, podremos ver el nodo de la documentación que hemos generado.

Referencias:
http://www.mono-project.com/Monodoc
http://www.mono-project.com/Generating_Documentation
http://people.mosaix.net/chris/tutorials/monodoc/monodoc-tutorial.html
http://msdn2.microsoft.com/en-us/library/5ast78ax(VS.71).aspx
Por el momento eso es todo, espero que este artículo les sea de utilidad y como siempre el proyecto y código relacionado a este artículo, están disponibles para su descarga en los siguientes archivos.
| Adjunto | Tamaño |
|---|---|
| Documentacion.tar.gz | 12.86 KB |
