Curso AppleScript: Variables, Locales, Globales y Propiedades, por Julifos

Una variable es como un cajón donde yo meto algo, y que después, si quiero, puedo utilizar.

Cuando yo digo 5 + 5, AppleScript me devuelve 10. Yo puedo almacenar ese valor en una variable y utilizarlo luego para otra cosa. Como siempre, lo que manda es el ejemplo activo, así que vamos allá.

tell application "Finder"

   set Cuantas_Cosas_Tengo to (count items of desktop)

end tell

display dialog "Tengo " &Cuantas_Cosas_Tengo & " cosas en el Escritorio."

En este ejemplo, AppleScript le pide al Finder que cuente los elementos que hay en el Escritorio, y almacena el resultado en la variable "Cuantas_Cosas_Tengo". Luego lo utiliza en un diálogo.

Vamos a hacer notar que las variables suelen ir en un color distinto por pura ergonomía y comodidad, y que su nombre no puede tener espacios ni caracteres

extraños o reservados (por ejemplo, no podemos acentuar la palabra "Cuántas", ni podríamos construir la variable "Canal_+", porque "+" es el operador matemático que corresponde a "sumar" y, por tanto, un carácter reservado.

Bueeeeno… He mentido. Sí que se puede, pero creo que es una pérdida de tiempo. No obstante, si nos ponemos muy tontos y queremos que nuestra variable se llame "la madre que me parió" o "50 * 15 = 750", entonces podemos hacerlo con las barras verticales (opción + 1), de esta manera:

set |la madre que me parió come (5/2) galletas| to 1

Para construir una variable hay dos maneras: con "set" y con "copy". A mí me gusta más la primera, aunque las dos hacen lo mismo (más o menos), por que "copy" puede causar confusión, al ser un comando que utilizan ciertas aplicaciones para copiar cosas al Portapapeles (el Finder, sin ir más lejos).

setx to 1

copy 1 to x

Sin embargo, cuando "duplicamos" una variable, por el motivo que sea, y como AppleScript es muy listo, lo que hace es "linkar" las dos variables al mismo valor. Así, cuando modifiquemos x, también cambiará el valor de xcopia. Esto se aplica solamente cuando los valores que encierran las variables son listas, records o script objects. En teoría también para los string, pero esto no tiene efecto; no se puede modificar, porque sus item no son realmente objetos. Veámoslo en este botón de muestra:

set item 2 of "kaka" to "i"

–> error

Para ilustrar el asunto de la duplicación de variables, un ejemplo vale más que mil palabras:

set x to {1,

2}

set y to x

set x’s item 1 to 5

x –> {5, 2}

y –> {5, 2}

Ambas variables comparten el mismo valor, que se ha actualizado dinámicamente. Por tanto, para hacer un duplicado real, y no una especie de link,

tendríamos que utilizar copy:

set x to {1,

2}

copy x to y

set x’s item 1 to 5

x –> {5, 2}

y –>{1, 2}

En el caso de las listas, también podríamos "destruir" el link utilizando set, tal que así (simpre se recomienda aun así, el uso de copy):

set y to x as linked list

Pero eso: para hacer duplicados de variables utilizaremos siempre copy.

¿linked list? Pues sí. Es una cosa que define applescript (un class) y que nadie utiliza, como ocurre con vector,

a quien le pasa tres cuartos de lo mismo. Creo que son más bien conceptos que utiliza AppleScript de manera interna y que no nos afectan demasiado. Si alguien quiere jugar un poco con los conceptos, le propongo el siguiente ejercicio:

{{1, 2}} as list

{{1, 2}} as linked list

Vea vd. mismo los resultados.

También decir sobre las variables que, evidentemente, si definimos una variable de nombre perros que tiene como valor el número entero 3, luego podemos utilizar esa variable como si fuera el mismo número 3. Por ejemplo:

set perros to 3

perros + 2

–> que devolverá el valor 5

set perros to perros -1 — uno que murió

–> devolverá el valor 2. O sea, su antiguo valor (3, definido en la primera línea), menos uno (que murió)

Por demás, las variables son "de usar y tirar". Una vez se han utilizado, la próxima vez que corra el script su valor volverá a ser el mismo qe se defina.

Las variables simples sólo tienen valor dentro de su propio nivel o ámbito de influencia (lo que llaman en inglés "scope"), que puede llegar a abarcar todos los límites de un "script object" o de un "handler".

De hecho, las variables son locales no explícitamente declaradas. Tanto las locales como las globales hacen una simple declaración (designando un nombre para el "cajón"), pero no establecen el valor. Las locales y las globales se declaran así:

local x

global y

… Y su valor se establece más adelante; las globales tendrán un ámbito mayor que las locales (o variables simples, a secas), pudiendo abarcar una subrutina entera (un "handler") o un "script object". Las locales, sin embargo, morirán al llegar al mar, como quien dijo, y no se suelen utilizar demasiado, porque basta con un simple "set nosequé to nosecuántos" para utilizar el valor sin andarse con locales ni vainas.

Entonces… ¿Para qué sirve "declarar" una local? Cuando se declara una variable local, las modificaciones a dicha variable durante la ejecución del script no se tienen en cuenta a la hora de terminar el script. Por defecto, cuando ejecutamos una aplicación de script que simplemente tiene la línea "set x to 1", podemos observar que cambia la fecha de modificación del script, porque se han "guardado los cambios" a dicha variable, aunque no tenga ninguna utilidad práctica. Sin embargo, si previamente hemos añadido la línea de código "local x" (por tanto, hemos declarado explícitamente la local "x"), AppleScript NO guarda esta vez los cambios en el script. ¿Y qué utilidad tiene eso? Pues es muy útil, por ejemplo, cuando nuestro script se va a ejecutar bajo ciertas condiciones, como por ejemplo: tenemos permiso para "ejecutar", pero no para "escribir" (o sea, para guardar los cambios); el script se halla en un disco no-escribible (un CD normal o un DVD); nuestras variables almacenan muchos datos que no queremos que cambien de tamaño nuestro script (por ejemplo, si tenemos la línea "set x to read esteMP3", después de ejecutarlo nuestro script tendrá un tamaño de 3 ó 4 MB más, que son los datos leídos del documento mp3, lo cual nos viene mal para enviarlo a alguien por correo electrónico).

De todas maneras, lo de guardar cambios depende de quién ejecute el script. Como hemos dicho, una aplicación normal (applet o droplet) sí guardará los cambios. También se hará desde un editor de scripts. Sin embargo, si ejecutamos nuestro script desde, por ejemplo, FastScripts (que dicho de paso, es una utilidad fantástica), no habrá cambios en el script. Pero, por lo general, sí los habrá.

Las globales y las propiedades, como hemos dejado dicho, tienen vigencia en todo el "script object", tanto dentro como fuera de un "handler", y su valor se mantiene una vez que el script ha terminado.

Y las propiedades, a diferencia del resto, tienen vigencia en todo el "script object" y al mismo tiempo que se declaran, establecen un valor inicial. Vamos a ver un ejemplo rápido.

property lo_uno : "Capullo"

property lo_otro : "Mamón"

display dialog "¿Crees que el jefe es un " & lo_uno & ", o más bien un " & lo_otro & "?" buttons {"Capullo", "Mamón"}

set el_jefe to button returned of the result

if el_jefe = "Capullo" then

   set lo_uno to "Capullo"

   set lo_otro to "Mamón"

else

   set lo_uno to "Mamón"

   set lo_otro to "Capullo"

end if

La primera vez que ejecutemos este script, la pregunta será: "¿Crees que el jefe es un Capullo, o más bien un Mamón?". Y luego, si el interpelado decide que es más bien un Mamón, la segunda vez que ejecutemos el script, la pregunta será: "¿Crees que el jefe es un Mamón, o más bien un Capullo?". Porque se habrá almacenado el valor de la anterior respuesta.

Las propiedades vienen muy bien, por ejemplo, cuando son "propiedades", en el sentido estricto de la palabra, y van a tener siempre el mismo valor. Por ejemplo, para establecer unas preferencias determinadas que van a durar para siempre. Imaginemos ahora este ejemplillo:

property nombre_del_usuario : ""

if nombre_del_usuario = "" then

   set nombre_del_usuario to text returned of ¬

      (display dialog "Por favor, teclee su nombre…" default answer "")

end ifdisplay dialog "Bienvenido, " & nombre_del_usuario

Aquí se supone que el usuario introduce su nombre la primera vez que corre el script y que, una vez almacenado su nombre, nunca más tendremos que preguntárselo. Gracias a la propiedad "nombre_del_usuario", hemos conseguido una aplicación personalizada para una persona concreta.

Creo que, en un futuro no muy lejano, las propiedades no se almacenarán en la aplicación. Por eso Apple recomienda guardar los datos necesarios en archivos de preferencias, que bien puede ser un simple archivo de texto, un XML o tal pascual.

Por tanto, si es que ha quedado claro, la persistencia y área de influencia de los distintos tipos de variables será asín:

Tipo Área de influencia Persistencia
Variable simple o local su mismo nivel muere al finalizar el script
Global todo el script object muere al finalizar el script
Property todo el script object persiste hasta que se cambia su valor

4 Comments

  1. Anónimo

    Si no recuerdo mal, en sus inicios el AppleScript tenía la intención de poder utilizarse en diferentes idiomas. ¿Qué ha sido de esa vieja idea? ¿Qué posibilidades hay de volver a ella? ¿Qué otros lenguajes hay para programar en español? De no haber nada que merezca la pena… ¿a qué se debe?

  2. Anónimo

    Me ha dejado consternado lo de las properties, creí que eran sencillamente variables globales con un nombre más bonito. Sin embargo, por las pruebas que he hecho en mi «Editor de Scipts», de una manera, que veo algo caprichosa, la property cambiada por cada ejecución se mantiene entre ejecución y ejecución pero si cierras y vuelves a abrir el script, claro, ya la pierde y vuelve a ser lo que hay escrito que debe valer en su definición inicial…

    Veo un poco peligroso depender de esto. Supongo Julifos que Apple antes de este comportamiento actual lo que hacía era modificar algún recurso del fichero con el fuente del Script… Algo, en tres palabras, im-pre-sionante.

  3. Anónimo

    Carajo!
    La idea de los dialectos murió. Creo que llegaron a existir los dialectos francés y japonés, pero no estoy seguro de que llegaran a utilizarse de manera «robusta».
    Yo no conozco ningún lenguaje donde los comandos estén en español. De todas maneras, y si estás altamente interesado, podrías elaborar una especie de semi-dialecto tú mismo. Existe un proyecto de Philip Aker llamado TextOSA. Básicamente, tú escribes lo que te dé la gana en cualquier editor que soporte OSA (el Editor de Scripts, Frontier, etc.) y lo compilas con tu componente personalizado OSA (por ejemplo, AppleScript, el JavaScript de Latenight Software, o tu nuevo componente). Por ejemplo, tú puedes escribir «variable ejemplo valor 5», y luego transformar «variable» a «set» y «valor» a «to», de tal manera que tú escribes en español y el código se compila en AppleScript normal y corriente (en inglés).
    Trabajo de chinos.

    Ende!
    Si guardas y ejecutas este código como aplicación:

    property x : «algo»
    set x to text returned of (display dialog «Di algo» default answer x)

    Verás que, efectivamente, como tú has descrito, el valor de una «property» modificada persiste de ejecución a ejecución. Estos cambios se guardan en el «scpt» de la aplicación (puedes comprobar que antes de la primera ejecución el script tiene «x» bytes, y después de ejecutarlo tiene «x» bytes + «y»; o, simplemente, que la fecha de modificación de la aplicación cambia cada vez que se ejecuta, porque se han guardado los cambios).
    En tu caso, haciendo la prueba desde el Editor de Scripts, los cambios se guardan en memoria. Mientras el script está abierto, las propiedades funcionan correctamente. Cuando lo cierras, la memoria se destruye y sólo se guarda lo que está escrito. En el Script Debugger, sin embargo, sí que se pueden guardar los cambios que se han producido en memoria. En Smile, si no me equivoco, sí se pueden guardar los cambios, pero estos se perderán al reabrir el script (si abres el script en Script Debugger, éste sí leerá correctamente los cambios).

    Ahora, en OS X y con las nuevas tecnologías, la cosa se ha puesto más chunga. Si, por ejemplo, el usuario que ejecuta la aplicación tiene permisos para «ejecutar», pero no para «escribir», las propiedades no persistirán. Utilidades como «FastScripts» tampoco guardan las propiedades. Por eso Apple recomienda en la actualidad guardar datos-que-deben-persistir en ficheros externos de texto (por ejemplo, los .plist o simples .txt), y en directorios donde se sepa que, en principio, hay permiso de lectura-escritura (por ejemplo, la carpeta de Preferences o de Application Support del usuario).

Deja una respuesta