You are currently browsing the monthly archive for octubre 2010.

La primera tarea del sistema de documentación automatizado doxygen es la creación de un manual de referencia del código del programa. Sin embargo, doxygen ofrece también la funcionalidad de añadir un texto libre. Por la capacidad de doxygen de entender etiquetas de HTML, podemos editar un documento HTML con un editor aparte y luego integrarlo en la documentación generada con doxygen. Esto nos trae la ventaja de poder entregar una documentación completa y actualizada con cada ejecución de doxygen.

Creación de documentación libre

Doxygen conoce varias etiquetas para la creación de documentación libre. En primer lugar están las etiquetas \mainpage, \page y \subpage para la creación y la estructuración de páginas independientes. Dentro de cada página podemos estructurar el texto en apartados con las etiquetas provenientes LaTeX: \section, \subsection, \subsubsection y \paragraph. Conviene guardar la documentación libre en un fichero aparte por no tener correspondencia a ninguna entidad de código en concreto. El sufijo previsto para estos ficheros es dox, es decir, podemos crear una carpeta “doc” o “dox” que incluye todos los ficheros fuente que contienen documentación pero ninguna línea de código ejecutable.

Las etiquetas mencionadas arriba deben encontrarse dentro de un comentario de documentación. Lo más conveniente en este caso es abrir el comentario con /** o /*! en la primera línea y cerrarlo con */ en la última. Doxygen no exige iniciar una línea en medio con *. Ver la documentación de doxygen para un ejemplo.

Lo normal sería escribir la documentación libre en un fichero de texto, pero como ya he mencionado, en este artículo queremos averiguar, si podemos utilizar fuentes escritos en HTML. Dentro de lo que cabe tenemos dos estrategias para usarlas:

  1. Crear un documento HTML que doxygen lee y interpreta como un fichero fuente, es decir, un fichero .dox, y
  2. integrar un documento HTML externo

Ambas maneras tienen ventajas y desventajas que detallaremos a continuación.

Procesar HTML como fichero fuente

Podemos crear un fichero HTML y dejarlo procesar por doxygen como si fuera un fichero fuente. Doxygen entiende la mayoría de las etiquetas de HTML. Las que no entiende son en primer lugar etiquetas de contenido dinámico como OBJECT o EMBED. Esto no es de extrañar ya que doxygen no es un navegador de Internet sino una herramienta de documentación. Lo que duele más que tampoco entiende las etiquetas de cabecera. A contrario de lo que diga la documentación, la versión 1.7.1 que yo probé, no reconoce nada de lo que aparece entre <HEAD> y </HEAD> y tampoco la etiqueta BODY. Estas etiquetas aparecen entonces como cualquier texto normal.

Doxygen tampoco reconoce el comentario de HTML <– –>. Por lo tanto no podríamos esconder la apertura del comentario de documentación /** dentro de un comentario para que no nos aparezca si abrimos el fichero HTML en un navegador. En fin, no es posible crear un documento HTML que queda perfecto tanto en un navegador y en el resultado de doxygen a la vez. Todavía necesitamos un poco de trabajo manual:

Creamos un fichero dox que contiene algo como lo siguiente

/** \page mi_pagina_html Mi página en HTML
<h1>Soy un título</h1>
<p>En esta página podemos hablar de asuntos <em>muy</em> importantes.</p>
*/

Entre la primera y la última línea copiamos todo lo que se encuentra entre las etiquetas <BODY> y </BODY> en el documento HTML. (En este caso sólo he puesto dos líneas.)

La ventaja de esta manera es que doxygen crea una salida homogénea con las otras partes de la documentación. Más interesante aún es que doxygen enlaza los nombres de identificadores con la referencia correspondiente. De esta manera podemos, por ejemplo, crear un manual de usuario de una biblioteca en que aparecen automáticamente las enlaces al manual de referencia de los objetos de que estamos hablando.

Incluir un documento HTML

A veces los documentos HTML no son tan simples para que podamos usarlo directamente con doxygen. Puede haber varias razones. Por ejemplo:

  • El documento HTML se quiere usar tal cual como una página de Internet.
  • El documento usa una hoja de estilo u otros enlaces. En este caso y el anterior no podemos quitar la cabecera.
  • El documento usa contenido dinámico con Javascript.
  • El documento usa contenido empotrado como vídeos o animaciones flash.

En todos estos casos no queremos perder las características del propio HTML. Lo que podemos hacer es crear un pequeño fichero dox con el contenido siguiente:

/** \page mi_otra_pagina_html Mi otra página HTML
\htmlinclude "mi_fichero.html"
(Este documento sólo está disponible en la versión HTML de la documentación.)
*/

Con esta fuente, doxygen crea una página en que incluye el documento HTML “mi_fichero.html”, pero sólo para la versión HTML de la documentación. Desgraciadamente no existe una etiqueta en doxygen, con que podemos escribir algo en todos los formatos menos HTML. Así aparece una página prácticamente vacía en los demás formatos. Sólo se ve la frase “(Este documento sólo está disponible en la versión HTML de la documentación.)“. Esta frase aparece también al final del documento HTML, pero visualmente se impone menos. Existen también comandos exclusivos para otros formatos como \latexonly, pero no podrán sustituir el contenido dinámico de una página HTML, desde luego.

Debemos añadir el directorio, donde guardamos los ficheros HTML a incluir, al EXAMPLE_PATH de la configuración de doxygen. Si no es posible que doxygen no encuentra los ficheros que incluimos.

La ventaja de incluir un documento HTML de esta manera es poder usarlo sin modificación y aprovecharse de toda la potencia que una página WEB ofrece. La desventaja es que doxygen no enlaza nombres de identificadores con el manual de referencia y en los formatos no HTML no aparece ningún su contenido. Sin embargo, en muchos casos esto no supone un problema, ya que no se crea una documentación en otro formato que HTML.

Una aplicación de este truco puede ser la inclusión de un manual de usuario u otro texto libre. Se puede escribir en un editor como Microsoft Word y guardarlo como una página HTML. Luego se incluye esta página mediante \htmlinclude en la documentación de doxygen. Así es posible mantener una documentación completa y actualizada en todo momento.

Una cosa que, por cierto, no funciona es usar el comando \link a un fichero interno para crear un enlace a este documento HTML en la documentación. El enlace, sí, estará en la documentación creada por doxygen, pero no el fichero que enlaza. Esto sólo se puede hacer para documentos con una URL de Internet pública.

Conclusión

Hemos visto dos maneras de incluir documentación adicional al manual de referencia que doxygen crea a partir del código. La capacidad de doxygen de interpretar muchas etiquetas HTML permite incluir documentos escritos en HTML en la documentación. Es una buena opción para documentos no interactivos. Para páginas HTML más complejos se ofrece incluir la página tal cual mediante \htmlinclude, que mantiene toda la potencia de una página interactiva, pero a coste de no poder verlo en los demás formatos que doxygen puede crear.

Referencias

En el artículo “Como organizar ficheros en carpetas” ya he descrito criterios a tener en cuenta a la hora de crear las carpetas de un proyecto informático. En este artículo quiero dar un ejemplo real con comentarios de como se pueden organizar las carpetas en el caso concreto de una aplicación en C++. Aunque se trata de un caso concreto, aporta muchas ideas que se pueden generalizar.

Presento las carpetas en formato de árbol. Es el formato habitual para mostrar una estructura de carpetas, sin embargo aleja mucho los elementos principales de la carpeta raíz que, por lo tanto, se ven más difícilmente en su conjunto. Sin embargo, creo que será suficiente tener este problema en mente.

Los nombres propuestos para cada carpeta aparecen en cursiva. Están en inglés, pero se pueden cambiar según conveniencia. Los nombres de las carpetas usan el guión bajo ‘_’ en lugar de espacios para nombres compuestos por varias palabras. Conviene no usar espacios en las rutas de ficheros, ya que pueden complicar el procesamiento.

Todo lo relacionado con el proyecto se encuentra en una carpeta raíz.

  • cfg: Ficheros de configuración cuyos contenidos dependen de la máquina en que corre el programa. Normalmente sólo habrá uno que contiene información como la dirección IP o el nombre del equipo en la red. Se debería guardar un fichero de configuración por defecto en la carpeta code.
  • code: La carpeta que contiene los ficheros fuentes y es la carpeta raíz para un control de versiones.
    • mi_lib: Cada biblioteca tiene su propia carpeta. El nombre de la carpeta se ajusta lógicamente a lo que hace la biblioteca. Conviene usar un nombre corto que puede usarse como prefijo en los nombres de los ficheros fuentes. También es posible sólo añadir el directorio code a la ruta de inclusiones y incluir los ficheros mediante una ruta relativa como #include "mi_lib/include/mi_cabecera.h". En Java, las carpetas deben tener el nombre del paquete a que corresponden.
      • doc: Ficheros de documentación y tutoriales a compilar junto con la documentación de los ficheros de código por el sistema de documentación automático. La documentación en esta carpeta completa el manual de referencia creado a partir de los ficheros fuente del programa.
      • include: Ficheros de inclusión y otros ficheros públicos.
      • lib: Ficheros “cpp” en C++ u otros ficheros privados. También es habitual llamar esta carpeta src. Yo prefiero no usar este nombre ya que todo dentro de la carpeta code es “source”. De hecho, la carpeta code se podría llamar source.
    • main: Para el programa principal también hay una carpeta. Esta tiene la misma estructura que las demás. En lugar de main se puede usar el nombre del programa como nombre de carpeta. Si tengo varios ejecutables, entonces conviene tener una carpeta main en cuya subcarpeta doc se encuentra la documentación del proyecto y donde se hace referencia a todos los ejecutables y bibliotecas del proyecto – en fin sobre todas las subcarpetas de la carpeta code.
      • cfg: Una carpeta adicional para el programa principal puede ser una carpeta con ficheros patrones para la configuración de la máquina. Estos ficheros se copian a la carpeta cfg y se modifican para la máquina del programador.
    • project: Esta es la carpeta contiene los ficheros creados por el IDE. Cuando añades la carpeta code al control de versiones deberás borrar algunos ficheros no fuentes creados por el IDE. Los nombres de estos ficheros son diferentes para cada IDE.
      • Eclipse: Se usas varios IDE, entonces crea una subcarpeta para cada uno. Eclipse sería un nombre adecuado para el IDE Eclipse. Puede haber otros nombres como NetBeans o VisualStudio. Si no te gustan los entornos gráficos puedes crear una carpeta makefile para ser usado desde una consola.
  • compiled: Todos los ficheros generados. La idea es poder borrar el contenido de esta carpeta por completo para hacer “limpieza”.
    • generated_doc: Documentación generada por sistema de documentación automáticos.
      • html: Esta carpeta crea doxygen para el formato HTML. Habrá más carpetas para otros formatos de documentación como LaTeX.
    • gcc: Una carpeta para cada compilador que se usa. Si sólo uso un compilador, entonces este nivel de carpeta no es necesario.
      • Debug: El compilador de C++ suele crear una carpeta para cada configuración. Una suele llamarse “Debug” y otra “Release”. Puede haber más carpetas para más configuraciones; por ejemplo para enlaces con diferentes bibliotecas.
        • exe: La carpeta de ejecutables contiene todos los ficheros binarios necesarios para utilizar el programa compilado. Puede haber ficheros de configuración por defecto que meramente se necesitan copiar. ¡Incluye esta copia en el makefile! Para una aplicación java, se puede considerar usar el nombre jar en lugar de exe.
        • obj: Ficheros intermedios creado por el compilador y no necesarios para la ejecución del programa. En Java, esta carpeta podría denominarse class.
  • ext: Bibliotecas externas. Cada componente tiene una carpeta propia. Es importante archivar la biblioteca externa junto con el proyecto, ya que una versión más moderna quizá no funcionará con el código propio. Para reducir el uso del disco duro puede ser útil guardar las bibliotecas externas físicamente en una carpeta común y hacerlas aparecer en la carpeta ext mediante un enlace (soft link) del sistema operativo (con el comando ln en Unix.)
  • io: Carpeta principal para ficheros temporales y de entrada y salida del programa. Se entiende que se pueden borrar todos estos ficheros sin perjuicio al funcionamiento del programa. En un entorno real, las subcarpetas de io pueden encontrarse en otros directorios. Esto se debería poder ajustar con los ficheros en la carpeta cfg. Para hacer pruebas sin ensuciar al resto del disco duro, se aprovecha la carpeta io dentro de la carpeta raíz del proyecto. Para archivar un proyecto no haría falta guardar los ficheros dentro de la carpeta io – sólo la estructura de los directorios.
    • in: Ficheros de entrada al sistema. Es la responsabilidad del programa de borrar los ficheros procesados.
    • out: Fichero de salida del sistema.  Es la responsabilidad del programa de no sobrescribir ficheros todavía no procesados. No es su responsabilidad de borrarlos, ya que esto haría el sistema que recibe los ficheros. En un sistema real, la carpeta out sería la carpeta in del sistema siguiente.
    • temp: Ficheros temporales del programa. Es la responsabilidad del programa de borrar los ficheros. Es la responsabilidad del programador que sólo el programa deja sus ficheros ahí y que pueda limpiar la carpeta con un simple “borra todo”.
    • trace: Conviene tener una carpeta especial para trazas.
  • documentation: Documentación que ni es generada ni un código fuente para un sistema de documentación automatizado. Estos son ficheros Word, Excel, PDF, imágenes, emails y cualquier otro editado y procesado por una mente humana.
    • emails: Correos electrónicos con el cliente y otras personas involucradas. No guardes todos los emails aquí. Sólo aquellos que documentan cambios en los demás documentos.
    • manuals: Manuales de usuario o de referencia editado por un ser humano. Aquellos creados por un un sistema de documentación automático se encuentran en la subcarpeta generated_doc de la carpeta compiled.
    • specification: La especificación del proyecto. Para proyectos grandes es importante separar la especificación de otra documentación ya que los ingenieros de prueba usan meramente la especificación para comprobar que un software cumple los requisitos.

Por la longitud del artículo se nota que la creación de un árbol de carpetas para un proyecto no es trivial. Aún así todavía faltan carpetas que pueden ser importantes como una web_doc_root para un proyecto de páginas web. Pero, en fin, es sólo un ejemplo.

Referencias

HTML tiene un elemento SELECT que permite el atributo multiple para poder seleccionar más que una opción a la vez. (Las selecciones mútliples se hacen normalmente pulsando la tecla Control mientras se seleccionan las opciones con el ratón.) El atributo multiple no tiene valor. Si no está, entonces el elemento SELECT sólo permite seleccionar una opción. Este artículo explica como puedo obtener múltiples opciones seleccionadas en un programa PHP.

PHP devuelve los datos enviados desde un formulario en la variable “súperglobal” $_REQUEST. La variable $_REQUEST es una unión de las variables súperglobales $_GET, $_POST y $_COOKIE. Por lo tanto, su contenido no depende si hemos recibido los datos via un “GET” o un “POST”. Es decir, es una buena opción en general.

La variable $_REQUEST es un array asociativo, donde los índices son los valores de los atributos id o name de los elementos de entrada en el formulario HTML enviado. A cada índice se asigna el contenido del elemento correspondiente. En un SELECT simple se devolvería la opción seleccionada si hay.

Por ejemplo, consideramos el siguiente SELECT de selección simple (nótese la ausencia del atributo multiple):

<SELECT id="mi_select">
    <OPTION value="hola mundo">Hola mundo</OPTION>
</SELECT>

Si hubiéramos seleccionado la opción “Hola mundo”, entonces, en PHP, la expressión $_REQUEST['mi_select'] tendría el valor 'hola mundo'. (El valor del atributo value del elemento OPTION.)

Sin embargo, si el elemento SELECT tuviera puesto el atributo multiple, entonces sólo obtendríamos el valor de la última opción seleccionado. Para obtener todas las opciones, el valor de $_REQUEST['mi_select'] debería ser un array. Esto conseguimos cambiando el id del elemento SELECT a mi_select[]. (Esto es el mismo nombre más los corchetes [].)

<SELECT id="mi_select[]" multiple>
    <OPTION value="hola mundo">Hola mundo</OPTION>
</SELECT>

Este pequeño truco causa que $_REQUEST['mi_select'] es un array. Ahora puedo hacer un bucle sobre todas las opciones seleccionadas.

foreach ($_REQUEST['mi_select'] as $option_value)
{
    // Haz algo con el valor de la opción seleccionada $option_value
}

En corto: Asigna un nombre terminado en corchetes “[]” a un elemento SELECT cuando tiene puesto el atributo multiple para poder extraer todas las opciones seleccionadas desde PHP.

Referencias

Escribe tu dirección de correo electrónico para suscribirte a este blog, y recibir notificaciones de nuevos mensajes por correo.

Únete a otros 56 seguidores

Archivos

octubre 2010
L M X J V S D
« Sep   Nov »
 123
45678910
11121314151617
18192021222324
25262728293031