viernes, 29 de septiembre de 2023

OOo Basic. Datos

Tipos de variables según nivel de procesamiento

Diferenciamos las variables según el tipo de datos que contienen, podemos diferenciarlas también en función de su ámbito de aplicación, pero cabe aun una tercera diferenciación en relación al nivel de procesamiento que requiere.




Normalmente dividimos el algoritmo en tres fases: input, procesamiento y output; y lo propio es que el trabajo directo del usuario con las variables (entrada de datos y asignación a variables) se produzca en la fase input, esto es, al inicio del algoritmo, y de una sola vez. 


Esta es una simplificación del funcionamiento de un algoritmo, igual que lo es la imagen representativa del mismo que acabo de mostrar. En la práctica, el proceso de input suele se más complejo y estar más interrelacionado y distribuido a lo largo del desarrollo del algoritmo.

En función de esta complejidad es posible diferenciar tres tipos de variables:
  • Las libres, que responden al funcionamiento simple descrito antes y que reciben asignación directa por parte del usuario mediante interface con los condicionantes que se hayan establecido en el programa.
  • Las condicionadas, cuyo contenido no es establecido directamente por el usuario, sino que resulta de la aplicación de la condicionalidad, lo que equivale a decir que su contenido queda establecido en la fase de procesamiento y no de input.
  • Y las delimitadas, que lo pueden ser de diferentes formas y a diferentes niveles, resultando éstos de la fase de procesamiento, pero que requieren intervención del usuario para concretar la asignación de datos.
Cuando esta tipología de variables se presenta en un algoritmo, podemos decir que las fases Input-Proceso se entremezclan (parcialmente), resultando de ambas una interacción compleja entre el usuario y el programa que no se ajusta al modelo básico-secuencial que es el que normalmente se representa en las explicaciones teóricas. 

Sin embargo no es nada extraño encontrarse con este tipo de desarrollo más complejo. Un ejemplo lo tenemos en el docap Escolarización combinada. Documento de Información a Familias, en el que podemos encontrar los tres tipos de variables:
  • Libres (no sujetas a la condicionalidad): 

sCentroOrdinNombre = InputBox("Nombre del centro:","Escolarización combinada. Centro ordinario","CP El Bosque Encantado")
sCentroOrdinLocalidad = InputBox("Localidad:","Escolarización combinada. Centro ordinario","Villar Torbila")
sCentroEspecNombre= InputBox("Nombre del centro:","Escolarización combinada. Específico","CPEE Vallermoso")
sCentroEspecLocalidad = InputBox("Localidad:","Escolarización combinada. Centro Específico","Olmeda")
        • Condicionadas (las resultantes del condicional if):
        If sAlumSexo = "1" Then
        sAlumTratam1 = "de la alumna"
        sAlumTratam2 = "escolarizada"
        ElseIf sAlumSexo = "2" Then
            sAlumTratam1 = "del alumno"
            sAlumTratam2 = "escolarizado"
        End If 
        • Delimitadas (resultantes también del condicional If)
        If sEtapaIniciales= "EI" Then
        sCurso = InputBox("Curso o nivel:","Alumnado. Datos escolares","1º/2º/3º")
        sNombreEqDir = InputBox ("Responsable del " &  sCentroOrdinNombre, "Responsable firmante")
        sCargoEqDir = InputBox ("Cargo directivo del/de la responsable del " &  sCentroOrdinNombre, "Responsable firmante","Director-Directora-J. de Estudios")
        ElseIf sEtapaIniciales = "EP" Then
        sCurso = InputBox("Curso o nivel:","Alumnado. Datos escolares","1º/2º/3º/4º")
        sNombreEqDir = InputBox ("Responsable del " &  sCentroEspecNombre, "Responsable firmante")
        sCargoEqDir = InputBox ("Cargo directivo del/de la responsable del " &  sCentroEspecNombre, "Responsable firmante","Director-Directora-J. de Estudios")
        End If

        Con estos ejemplos queda claro que mientras que las condicionadas no requieren intervención del usuario, ya que el contenido o dato resulta de la condicionalidad y es asignado directamente a las variables por el algoritmo, las delimitadas requieren de nuevo la participación del usuario, el cual debe intervenir una vez que actúa la condicionalidad con los siguientes posibles resultados:
        • Presencia/Ausencia de presentación de la variable al usuario
        • Alteración del contenido solicitado en función de la condicionalidad
        • y/o acotamiento o delimitación de las opciones de respuesta disponibles al usuario en función de la condicionalidad.
        El modo en que cumplimentemos las variables libres y las delimitadas dependerá de las opciones disponibles en el lenguaje y de la forma que el autor del docap de a la interface. Una forma simple y eficiente consiste en utilizar InputBox() como recurso para ambos tipos de variables, o usar controles de formulario para las variables libres e InputBox() para las delimitadas.

        OOo Basic. Datos

         Variables privadas (locales) y variables públicas

        Además de por el tipo de datos que contienen, podemos diferenciar las variables también por su ámbito de aplicación o, por decirlo de otro modo, desde qué componentes de la estructura del algoritmo  son accesibles los datos que contienen




        Aunque podemos diferenciar distintos ámbitos (Mauricio Baeza, por ejemplo, diferencia 4: local, privado, público y global), pero por ahora me limitaré a diferenciar dos por la funcionalidad que tiene dicha diferenciación en cuanto a la creación de docap: el ámbito privado (asumiendo dentro de él el concepto "variable local" en la definición de Baeza) y el ámbito público. Explicaré esta diferenciación partiendo de su aplicación práctica más simple y de utilidad más inmediata: la programación lineal empleando macros complejas vs. uso modular de macros simples (1).

        Esta diferenciación es fundamental para abordar dos modos de plantear el desarrollo del código, así que la diferenciación entre variables privadas y públicas es de especial utilidad.

        Como ya sabes, cuando creamos una macro (por ejemplo) en Writer para (por ejemplo) automatizar la creación de un documento, normalmente empezamos haciendo uso de la funcionalidad Grabar macro, disponible desde el menú Herramientas|Macros|Grabar macro.

        También sabes que el resultado de utilizar Grabar macro es un código delimitado por Sub NombreMacro - End Sub, que contiene unas cuantas líneas comentadas y que inicia con una declaración de dos variables de tipo objeto y la correspondiente asignación de contenido a dichas variables. De este modo se identifica como referencia de las acciones el documento desde el que se llama a la macro y la instancia que ejecuta las mismas es el objeto-servicio dispatcher. Todo lo demás son funciones de ejecución de órdenes (las que graba el sistema cuando usamos el teclado mientras está activa la funcionalidad Grabar macro), las cuales pueden ser simples o directas o aplicarse sobre estructuras matriciales previamente definidas. En cualquier caso, puedes apreciar una enumeración sucesiva de elementos/acciones que refleja claramente el carácter secuencial del modelo de programación que subyace.

        Frente a este procedimiento, podemos idear un uso diferente de Grabar macro que, en lugar de utilizar esta funcionalidad para generar el documento, sea empleada para generar secuencias de código que ejecutan exclusivamente una orden. Esta secuencias serán empleadas después tanto modular como secuencialmente con el objetivo de construir la secuencia de órdenes que nos interesa para desarrollar el algoritmo en su conjunto.

        Mientras que en el primero de los escenarios no tiene sentido diferenciar entre variable privada y variable pública, puesto que las dos únicas sólo se presenta en una ocasión y lo hacen como privadas), cuando nos planteamos trabajar siguiendo la lógica modular, nos enfrentamos a una repetición sistemática de la misma estructura, tantas veces como macros (simples) necesitemos utilizar. En esta caso parece evidente que tanta repetición resulta innecesaria, así que aquí sí cobra relevancia la diferenciación entre variables privadas y variables públicas o, mejor dicho, podemos optar hacer uso privado de las variables de objeto y repetirlas tantas veces como sea necesario, o convertirlas en variables públicas.

        ¿Pero cómo se hace esto y cuáles son sus consecuencias?, ¿por qué esta conversión privado-público puede ser ventajosa? Para responder a estas cuestiones, vayamos por partes, empezando por el final, por eso del ahorro de trabajo. Un ejemplo:



        • La conversión privado-público tiene sentido si las variables se seguir usando (siguen siendo accesibles) por cada una de las macros simples.
        • Esta conversión garantiza precisamente la accesibilidad al contenido de esas variables desde cualquier script o macro del módulo y de cada módulo dentro de la biblioteca (library-> librería)
        • La ventaja básica es la simplificación del código y la reducción del número de líneas. Manteniendo el funcionamiento autónomo de cada macro, para un programa formado por (por ejemplo) 12 macros, obtendremos un ahorro neto de 32 líneas de código, 44 si nos planteamos un funcionamiento integrado del conjunto.  
        • También implica un uso coherente de la modularidad, especialmente si optamos por la segunda de las opciones anteriores.
        • La conversión de una variable privada en pública es tan simple como trasladar la declaración de la variable de dentro de la macro (privada o local) a fuera de la misma y (preferible) al inicio del módulo. En ambos caso (privada-pública) la declaración de las variables (en OOo Basic, pero también en VBA) se inicia con la expresión Dim (también puedes usar dim), siendo únicamente relevante la diferenciación en el posicionamiento: dentro vs. fuera de la macro.
        Los pasos a dar para realizar la conversión planteada, partiendo del ejemplo anterior supone:
        1. Extraer las variables objeto de la macro y ubicarlas al inicio del módulo.
        2. Crear un nuevo script cuya función consiste únicamente en asignar los objetos a las variables (ahora) públicas.
        3. Si deseamos garantizar el funcionamiento individual de cada macro, realizamos una llamada al script anterior al inicio de cada macro.
        4. Si optamos por un funcionamiento integrado del conjunto resultante de la combinación de macros que conformar nuestro docap, entonces es suficiente con realizar esta llamada desde la macro que resuma la secuencia del proceso.

        Option Explicit
        dim document   as object
        dim dispatcher as object 

        sub MacroParrafo1
        Call VarSis
        dim args1(0) as new com.sun.star.beans.PropertyValue
        args1(0).Name = "Text"
        args1(0).Value = "Aquí va el texto del párrafo"
        dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args1())
        End Sub

        El texto anterior podría ser un ejemplo del proceso, repitiendo la llamada a VarSis desde cada macro individual. La alternativa (macros combinadas) supone no realizar esa llamada desde cada macro individual, pero sí desde la que gestiona la secuencia de macros que conforman el docap. La posición de la llamada a VarSis al inicio de esta macro de gestión es fundamental para el funcionamiento del conjunto.

        Sub EscrituraTexto

        Call VarSis

        InicioPag
          JustificarTexto
        MacroParrafo1
        MacroParrafo2
        MacroParrafo3
        MacroParrafo4
        CentrarTexto
        MacroParrafo5
        MacroParrafo6
        MacroParrafo7

        End Sub

        NOTAS

        (1) La diferenciación Privada-Publica que hace Maurico Baeza (2007) en "Aprendiendo OOo Basic"  resulta irrelevante para los fines de este blog, ya que la privacidad o delimitación modular de las variables privadas no es funcional según él mismo comprueba, lo que genera confusión. De ahí que yo prefiera denominar privadas a las que él denomina locales, suprimiendo la categoría variable privada (acotada al ámbito del módulo). 

        lunes, 18 de septiembre de 2023

        OOo Basic. Script

        Crear macros desde el IDE

        Aunque Grabar macro siempre será una funcionalidad útil, lo cierto es que su uso intensivo como recurso para automatizar un documento presenta  limitaciones, especialmente si el documento es de cierta extensión y no presenta mayor complicación en términos de formato.



        En cierto modo de este tema ya se ha hablado en este blog, pero no de forma tan explícita como pretendo ahora, siendo la causa de "retomar" este tema y plantear esta perspectiva, la colección de vídeos que estoy publicando en mi [canal You Tube] dentro de la lista [Competencia Digital Para Orientadores] (aunque sería apropiado que se titulara Ofimática Para Orientadores), en la que estoy presentando el proceso de creación de un docap (documento-aplicación) que automatiza la creación de un instrumento para la comunicación con familias.

        Inicialmente genero un docap basado en macros simples empleadas desde un planteamiento modular, obviando la opción simple de crear una macro completa desde Grabar macro, pero haciendo un uso instrumental de esta funcionalidad.

        Pretendo en esta entrada enlazar la fase previa, en la que se hace uso exclusivo de Grabar macro, y la estrategia de utilizar esta funcionalidad como ayuda en la creación de docap, aunque la creación de las macros individuales se realizar de forma directa desde el IDE.

        Precisamente es esta una buena explicación de la diferencia entre ambas estrategias: 

        En la primera, el usuario simplemente debe activar Grabar macro y proceder a "escribir" y formatear el documento tal y como desea que se reproduzca automáticamente.
          • Este enfoque no requiere acceder al IDE y mucho menos entender el código generado por Grabar macro.
          • Incluso nuestro usuario se puede permitir  cometer errores, aunque cuantos menos mejor.
          • Y también favorece el buen desarrollo de la macro tener estudiada la sucesión de acciones a desarrollar.
        La segunda requiere el análisis de la secuencia de acciones a desarrollar para identificar qué cuantas son y en qué orden se producen, pero también requiere acceder al IDE para trabajar desde él y conocer el código que genera Grabar macro en cada una de las acciones posibles.

          • Al contrario del primer enfoque, en este la escritura de textos y la extensión de los mismos no constituye problema alguno, ya que combina el conocimiento del procedimiento (la sintaxis de la macro de escritura) con el copia-pega del texto, lógicamente donde corresponda.
          • Tampoco supone un problema la repetición de las mismas acciones, por frecuentes que sea ésta, ya que sólo necesita grabar una vez cada acción para reutilizarla tantas como sea necesario, haciendo uso del enfoque modular.   

        Es precisamente este enfoque modular, junto con la familiaridad en el uso del IDE y el conocimiento del código, lo que caracteriza esta estrategia que diferencia al usuario familiarizado con la creación de macros en un usuario capaz de dominar la creación de docap aun simples, pero funcionales, basados en el "lenguaje de macros" en sentido estricto.

        Cierto que aun no dispone de herramientas para personalizar las macros que crea, pero la implementación de variables es un paso relativamente fácil de dar, si bien para ello se debe acercar a lo que implica Combinar correspondencia para intuir este concepto, con los riesgos que esto entraña; por ello siempre será mucho más útil y funcional acceder a este nivel de conocimiento mediante algún tipo de instrucción.

        Las necesidades de estudio y aprendizaje se acentúan conforme se adentra uno en la creación de soluciones adaptadas al quehacer profesional. 

        Para finalizar esta entrada, te dejo enlace a los dos documentos, [el primero] basado en el uso lineal de Grabar macro y [el segundo] creado utilizando el enfoque modular. Recuerda que tienes que descargarlos y abrirlos desde Libre Office. Para una explicación detallada de las diferencias entre ambos puedes acceder a [este vídeo].



        viernes, 1 de septiembre de 2023

        OOo Basic. Archivos.

         Rutas a directorios y archivos

        Aunque el trabajo cotidiano y directo con los servicios de LibreOffice resuelve el manejo de rutas y la creación de archivos y directorios de forma integrada con las utilidades básicas del sistema operativo, haciendo que parezca simple lo que es en realidad complejo; pero también nos podemos encontrar con la necesidad de gestionar el uso de rutas y el acceso a directorios y archivos desde OOo Basic.

         

        LibreOffice hereda de OpenOffice la cualidad de ser multiplataforma, por lo que hace uso de rutas de archivo y directorios en formato URL.

        file:///home/usuario/Directorio/archivo.ods

        En este formato se usan los caracteres 0-9, a-z y A-Z, siendo convertidos el resto a una codificación establecida. Por ejemplo, el espacio en blanco se convierte en %20. Es conveniente, por tanto, utilizar siempre caracteres aceptados por el formato URL.

        Además OOo Basic posee dos funciones muy útiles para trabajar con formato URL:

        • ConvertToUrl()
        • ConvertFromUrl()
        La primera (ConvertToUrl) convierte una ruta al formato URL y la segunda (ConvertFromUrl) devuelve la ruta al formato local. Veamos en un pseudoscript (basado en uno de Mauricio Baeza) para ejemplificar su uso:

        Sub UsoRuta

        Dim sRuta As String

        sRuta = "/home/yomismo/MiArchivo.ods"  -> establezco la ruta local (Windows)

        MsgBox sRuta -> y la muestro

        sRuta = ConvertToUrl("/home/yomismo/MiArchivo.ods") -> Convierto a formato URL

        MsgBox sRuta  -> Y la muestro en este formato 

        sRuta = ConvertFromUrl( sRuta ) -> Regreso al formato local originario

        MsgBox sRuta -> Y compruebo que efectivamente es así

        End Sub

        Fíjate en la diferencia entre el uso de una y otra función, ya que son inversas y complementarias, tanto en su sintaxis como en su funcionamiento. 

        Siempre que vayamos a trabajar con rutas para acceder a archivos o guardarlos en directorios es conveniente utilizar la función ConvertToUrl() para evitar errores en el acceso. En este contexto, ConvertFromUrl() te puede servir para comprobar que todo funciona según tienes previsto.

        Procedimientos. Datos.

        Calc. Crear y acceder a un libro

        En esta entrada explicaré cómo crear un nuevo libro (y acceder a uno ya creado) desde otro libro Calc que sirve a modo de gestor.


        puede que a alguien se le ocurra plantear que antes de aventurarse por estos derroteros no estaría de más responder a una pregunta muy simple pero fundamental: ¿para qué?.

        Realmente es fácil dejarse llevar por la magia de la programación y abordar este objetivo sin reflexionar en su potencial interés y/o utilidad, pero aquí no estamos principalmente para aprender a programar (iba a decir para perder el tiempo, pero no sería ni justo ni exacto) , así que primero deberemos responder a una pregunta tan simple como pertinente.

        Crear un libro Calc desde otro que previamente ha tenido que ser creado, suena a algo así como llevar agua a la fuente, pero no lo es necesariamente. Tal vez si digo crear un documento Writer desde un libro Calc, el tema empiece a ponerse un poco más  interesante.

        Crear un documento Writer desde Calc suena a posibilidades: posibilidades de desarrollar una ficha de recogida de datos, un informe de actuaciones, el documento-base de un acta, un informe personalizado de los resultados de la aplicación de una prueba... Esto es, se nos abre un mundo de posibilidades pensando en la combinación de la sencillez del uso de formularios en Calc con la redacción de un documento en Writer... una vez, claro está, que sabemos cómo crear y trabajar con un formulario en Calc y cómo crear un texto en Writer desde un script.

        Pues bien, según en qué circunstancias y condiciones, crear un libro Calc con funciones similares a lo que supone crear un documento Writer puede ser una solución tanto o más interesante que utilizar Writer como servicio complementario. Esto es así por las funcionalidades que tiene Calc en el manejo de datos, tanto en lo referente a la dimensión formal como al tratamiento de datos mediante funciones y su representación gráfica. Cierto que para algunas de ellas (de las posibilidades anteriores) deberemos trabajar con libros previamente diseñados con determinados fines, no con libros en blanco, pero para otras, e incluso para el tratamiento masivo de datos desde otras aplicaciones, crear y trabajar con esos documentos en blanco, "formateados" mediante código en el momento de su creación, puede ser suficiente, cuando no una solución más eficiente (aunque sólo sea por el ahorro de trabajo previo).

        Algunos ejemplos de la utilidad del trabajo sobre Calc desde Calc podría ser lo que se presenta ahora (aunque también como opción de continuidad) como soporte para la recogida de datos sobre la aplicación de pruebas: en este caso, la propuesta que supone esta estrategia (Calc desde Calc) es diferenciar la fase recogida y tratamiento de datos de la fase archivo de resultados. Optar por Calc en lugar de Writer es dejar abierta la posibilidad de un posterior trabajo (potencialmente sistematizado además) con esos datos, en lugar de una "mera" exposición de resultados como representa la opción Writer, por más que deje abierta (lo que no es poco) la posibilidad de perfilar el análisis necesariamente estandarizado que implica la creación de ese documento mediante código.

        Otra aplicación puede ser la de diferenciar la fase de recogida y tratamiento de datos en un proceso de análisis grupal de resultados y la elaboración de una síntesis individual, formalizada en formato ficha, evitando recargar el documento originario con multitud de síntesis individuales, algo que, aunque parezca funcional, si el número de estas fichas es elevado, termina siendo muy poco manejable y el archivo excesivamente pesado.

        Contestada, espero que convenientemente, la pregunta nada baladí del inicio, paso ahora a explicar el cómo, aunque la respuesta es muy simple y un ejemplo (de Mauricio Baeza) mucho más ilustrativo que una larga explicación:

        Sub CrearLibroNuevo

        Dim sRuta As String

        Dim mArg()

        Dim oNuevoLibro As Object

        sRuta = "private:factory/scalc"

        oNuevoLibro = StarDesktop.loadComponentFromURL( sRuta, "_default", 0, mArg() )

        End Sub

        Viene a decir el autor (Mauricio) que el método  loadComponentFromURL es el responsable de la creación de nuevos documentos, además de cualquier servicio L.O. (excepto de base de datos), siendo suficiente con especificar qué servicio en la fórmula private:factory/scalc, donde scalc se puede sustituir por swriter, simpress o sdraw

        El método loadComponentFromURL pertenece, a su vez, al servicio com.sun.star.frame.XComponentLoader, que se resume como StarDesktop para facilitar la sintaxis de la expresión.

        A partir de aquí podremos trabajar con este nuevo documento creado (vg., nuestro nuevo libro Calc), cosa que plantearemos en entradas posteriores.

        Si nuestra opción es utilizar un libro Calc (o cualquier otro documento) creado con una función específica (ya anticipamos antes esta posibilidad) a modo de modelo (algo similar a lo que hicimos en entradas anteriores con una hoja-modelo), entonces deberemos recurrir a un procedimiento similar al empleado para crear un documento nuevo, pero sustituyendo la formulación de la asignación a la variables sRuta:

        • En vez de  sRuta = "private:factory/scalc" (que crea un nuevo archivo Calc)
        • ... usaremos sRuta = ConvertToUrl("NombreDeLaRutayElArchivoConExptensión" )
        ... con lo que el script queda como sigue (basado también en Mauricio Baeza):

        Sub AbrirLibro

        Dim sRuta As String

        Dim mArg()

        Dim oDocumento As Object

        sRuta = ConvertToUrl( "TuRutaTuArchivo" )

        oDocumento = StarDesktop.loadComponentFromURL( sRuta, "_blank", 0, mArg() )

        End Sub

        NOTA

        Para entender o recordar el uso de directorios y rutas te sugiero que revises [esta entrada].