Programando en Ruby

La Guía de los "Programadores Pragmáticos"

Ruby y su mundo



Es un hecho desafortunado el que nuestras aplicaciones tengan que lidiar con el ancho y cruel mundo. En este capítulo echaremos un vistazo a cómo interactúa Ruby con su entorno. Los usuarios de Microsoft Windows también estarán interesados en mirar la información específica a esta plataforma en la página 163.

Argumentos de la línea de comandos

``In the Beginning was the Command Line.''[Título de un maravilloso ensayo de Neal Stephenson (disponible online en http://www.spack.org/essays/commandline.html).] Independientemente del sistema en el que Ruby se esté ejecutando, sea una super estación de trabajo científica o un dispositivo embebido como un PDA, es necesario iniciar el intérprete de algún modo, y ésto nos proporciona la posibilidad de pasarle argumentos desde la línea de comandos.

Una llamada al comando Ruby consta de tres partes: las opciones para el intérprete Ruby, opcionalmente el nombre de un programa a ejecutar, y opcionalmente un conjunto de argumentos para ese programa.

ruby [
            opciones
            ] [--] [
            archivoprograma
            ] [
            argumentos
            ]

Las opciones Ruby acaban con la primera palabra en la línea de comandos que no empieza por un guión, o por el carácter especial ``--'' (dos guiones).

Si no se indica nombre de archivo en el comando, o si el nombre del archivo es un simple guión (-), Ruby lee el código del programa desde la entrada estándar.

Los argumentos para el programa en sí mismo siguen al nombre del programa. Por ejemplo:

% ruby -w - "Hello World"

habilitará las advertencias, leerá el programa de la entrada estándar, y pasará la cadena "Hello World" como argumento.

Opciones de la línea de comandos

-0[octal}
' The number ``0'' flag specifies the record separator character (\0, if no digit follows). -00 indicates paragraph mode: records are separated by two successive default record separator characters. -0777 reads the entire file at once (as it is an illegal character). Sets $/.

-a
' Auto split mode when used with -n or -p; equivalent to executing {$F at the top of each loop iteration.

-C directorio
' Cambia el directorio de trabajo a directorio antes de la ejecución.

-c
' Comprueba solo la sintaxis; no ejecuta el programa.

--copyright
Imprime la información sobre los derechos de autor y sale.

-d, --debug
' Establece $DEBUG a true. Ésto podrías usarlo en tus programas para activar trazas adicionales.

-e 'comando'
' Ejecuta comando como una línea de código Ruby. Se permiten varios -e, y los comandos se tratan como múltiples líneas en el mismo programa. Si archivoprograma se omite cuando -e está presente, la ejecución se detiene después de que los comandos -e se ejecuten.

-F patrón
' Especifica el separador de campos ($;) a usar por defecto en split() (afecta a -a).

-h, --help
' Muestra una pequeña pantalla de ayuda.

-I directorios
' Especifica los directorios que deben añadirse al comienzo de $LOAD_PATH ($:). La opcion -I puede aparecer varias veces, y también pueden aparecer varios directorios a continuación de cada -I. Los directorios deben separarse por ``:'' en sistemas tipo Unix y por ``;'' en sistemas DOS/Windows.

-i [extensión}
' Edits ARGV files in place. For each file named in ARGV, anything you write to standard output will be saved back as the contents of that file. A backup copy of the file will be made if extension is supplied.
% ruby -pi.bak -e "gsub(/Perl/, 'Ruby')" *.txt

-K kcode
' Especifica el conjunto de caracteres a usar. Esta opción es útil principalmente cuando se usa Ruby para procesado del idioma japonés. kcode puede tomar los siguientes valores: e, E para EUC; s, S para SJIS; u, U para UTF-8; o a, A, n, N para ASCII.

-l
' Habilita el procesado automático del fin de línea; establece $\ al valor de $/ y procesa todas las líneas de entrada automáticamente.

-n
' Coloca el bucle ``while gets; ...; end'' alrededor de tu programa Por ejemplo, un comando grep simple podría implemetarse así:
% ruby -n -e "print if /wombat/"  *.txt

-p
' Coloca tu código dentro del bucle ``while gets; ...; print; end.''
% ruby -p -e "$_.downcase!" *.txt
-r librería
' Hace un require de la librería indicada antes de la ejecución.

-S
' Busca el archivo del programa usando las variables de entorno RUBYPATH o PATH.

-s
' Cualquier opción de línea de comandos que aparezca entre el nombre del programa y el nombre de un archivo o un --, se borra de ARGV y se crea una variable global con el nombre de esa opción. En el siguiente ejemplo, se crearía una variable $opt con valor ``electric''.

% ruby -s prog -opt=electric ./mydata

-T[level}
' Establece el nivel de seguridad, el cual entre otras cosas habilita las comprobaciones de contaminación. (consultar página 253). Establece $SAFE.

-v, --verbose
' Activa el modo informativo e imprime el número de versión. En modo informativo se muestran las advertencias de compilación. Si no se especifica nombre de programa en la lína de comandos, Ruby sale.

--version
Muestra el número de versión de Ruby y sale.

-w
' Activa el modo informativo. Al contrario que -v, lee el programa desde la entrada estándar si no se especifica ningún archivo de programa. Recomendamos que ejecutes tus programas Ruby con -w.

-X directorio
' Cambia el directorio de trabajo a directorio antes de la ejecución. Equivalente a -C directorio.

-x [directorio}
' Elimina el texto anterior a la línea #!ruby y cambia el directorio de trabajo a directorio si se indica.

-y, --yydebug
' Habilita la depuración de yacc en el procesador de código (waaay muchísima información).

ARGV

Todos los argumentos de la línea de comandos despues del nombre del programa son accesibles por tus programas Ruby a través del array global ARGV. Por ejemplo, invocar Ruby así

% ruby -w ptest "Hello World" a1 1.6180

produce un array ARGV de contenido ["Hello World", a1, 1.6180]. Existe una diferencia para todos los que seais programadores de C---ARGV[0] es el primer argumento del programa, no el nombre del programa. El nombre del programa actual está disponible en la variable global $0.

Finalización de un programa

El método Kernel#exit finaliza tu programa, devolviendo un valor al sistema operativo. Sin embargo, a diferencia de otros lenguajes, exit no termina el programa inmediatamente. Kernel#exit primero lanza una excepción SystemExit , la cual puedes capturar, y después realiza una serie de tareas de limpieza, incluyendo ejecutar todos los métodos at_exit existentes y los destructores de objetos. Consulta la referencia de Kernel#exit al comienzo de la página 415 para más detalles.

Variables de entorno

Puedes acceder a variables de entorno del sistema operativo usando la variable predefinida ENV. Responde a los mismos métodos que Hash.[ENV no es realmente una Hash, pero si es necesario, puedes convertirla a una Hash usando ENV#to_hash.]

Los valores de algunas variables de entorno son leídas por Ruby cuando comienza. Estas variables modifican el comportamiento del intérprete, tal y como se muestra en la tabla 13.1 en la página 139.
Variables de entorno usadas por Ruby
Nombre de la variable Descripción
RUBYOPT Opciones de línea de comandos adicionales para Ruby; se examina después de que las opciones reales de la línea de comandos sean procesadas ($SAFE debe valer 0).
RUBYLIB Rutas de búsqueda adicionales para los programas Ruby ($SAFE debe valer 0).
RUBYPATH Con la opción -S, establece la ruta para la búsqueda de programas Ruby (por defecto se busca en PATH).
RUBYSHELL Shell a usar cuando se creen nuevos procesos; si no está establecida también se consultará SHELL o COMSPEC.
DLN_LIBRARY_PATH Ruta de búsqueda para módulos cargados dinámicamente.
RUBYLIB_PREFIX (Solo Windows) Altera la ruta de búsqueda RUBYLIB añadiendo este prefijo a cada componente.

Escribir en variables de entorno

Un programa Ruby puede escribir en el objeto ENV, el cual en muchos sistemas modifica los valores de las variables de entorno correspondientes. Sin embargo, este cambio es local al proceso que lo hace y a los hijos que cree a partir de ese momento. Esta herencia de variables de entorno se ilustra en el código que sigue. Un subproceso cambia una variable de entorno y este cambio se ve en un proceso que empieza en ese momento. Sin embargo, el cambio no es visible al padre original. (Ésto viene a demostrar que los padres nunca saben con certeza qué es lo que están haciendo sus hijos.)

puts "In parent, term = #{ENV['TERM']}"
fork do
  puts "Start of child 1, term = #{ENV['TERM']}"
  ENV['TERM'] = "ansi"
  fork do
    puts "Start of child 2, term = #{ENV['TERM']}"
  end
  Process.wait
  puts "End of child 1, term = #{ENV['TERM']}"
end
Process.wait
puts "Back in parent, term = #{ENV['TERM']}"
produce:
In parent, term = xterm
Start of child 1, term = xterm
Start of child 2, term = ansi
End of child 1, term = ansi
Back in parent, term = xterm

Dónde busca Ruby sus módulos

Se usa require o load para incorporar módulos en tus programas Ruby. Algunos vendrán suministrados con Ruby, otros los instalarás del Ruby Application Archive, y otros los programarás tu mismo. ¿Cómo hace Ruby para buscarlos?

Cuando Ruby se compila para una máquina en particular, predefine un conjunto de directorios estándar para mantener el material relacionado con las librerías. Por lo tanto, éstos dependen de la máquina en cuestión. Puedes comprobar cuales son estos directorios desde la línea de comando con algo así:

% ruby -e 'puts $:'

En ordenador Linux típico, probablemente verás algo así:

/usr/local/lib/ruby/site_ruby/1.6/i686-linux
/usr/local/lib/ruby/site_ruby/1.6
/usr/local/lib/ruby/site_ruby
/usr/local/lib/ruby/1.6/i686-linux
/usr/local/lib/ruby/1.6
.

Los directorios site_ruby están pensados para mantener módulos y extensiones añadidos por ti. Los directorios dependientes de la arquitectura (i686-linux en este caso) continen ejecutables y otras cosas específicas a esa máquina en particular. Todos estos directorios se añaden automáticamente en las búsquedas de módulos de Ruby.

En algunas situaciones esto no es suficiente. Quizá estés trabajando en un gran proyecto Ruby, y tu y tus colegas habeis creado una gran cantidad de código Ruby. Tú quieres que todo el mundo en el equipo tenga acceso a todo el código. Tienes un par de opciones para realizar esto. Si tu programa se ejecuta en el nivel de seguridad cero (consulta el comienzo del Capítulo 20 en la página 253), puedes establecer la variable de entorno RUBYLIB a una lista de uno o mas directorios para buscar en ellos.[El separador entre entradas depende de tu plataforma. Para Windows es un punto y coma; para Unix, dos puntos.] Si tu programa no es setuid, puedes usar el parámetro de la línea de comandos -I para hacer lo mismo.

Finalmente, la variable Ruby $: es un array de lugares donde buscar archivos para cargar. Esta variable se inicializa con la lista de directorios estándar, más cualquier añadido que especifiques usando RUBYLIB y -I. Siempre podrás añadir directorios adicionales a este array desde tu propio programa.

Entorno de compilación

Cuando Ruby se compila para una arquitectura concreta, todas las configuraciones relevantes a la hora de compilarlo (incluyendo la arquitectura, opciones del compilador, directorio del código fuente, y más) se escriben en el módulo Config dentro del archivo de librería ``rbconfig.rb''. Después de la instalación, cualquier programa Ruby puede usarlo para obtener detalles sobre como se compiló Ruby.

require "rbconfig.rb"
include Config
CONFIG["host"] » "i686-pc-linux"
CONFIG["LDFLAGS"] » "-rdynamic"

Las librerías usan este archivo de configuración para compilar y enlazar correctamente en una arquitectura en concreto. Consulta el comienzo del Capítulo 17 en la página 169, y la referencia de mkmf en la página 451 para más detalles.


Extraído del libro "Programming Ruby - The Pragmatic Programmer's Guide"
Copyright © 2000 Addison Wesley Longman, Inc. liberado bajo los términos de la Open Publication License V1.0.
La referencia está disponible en: download.