ejemplos - ruby on rails tutorial español pdf
Opción de línea de comandos realmente barata en Ruby (19)
EDITAR: por favor , lea los dos requisitos enumerados en la parte inferior de esta publicación antes de responder. La gente sigue publicando sus nuevas gemas y bibliotecas y todo lo demás, lo que claramente no cumple con los requisitos.
A veces quiero piratear algunas opciones de línea de comandos en un script simple. Una forma divertida de hacerlo, sin ocuparse de getopts o análisis ni nada de eso, es:
...
$quiet = ARGV.delete(''-d'')
$interactive = ARGV.delete(''-i'')
...
# Deal with ARGV as usual here, maybe using ARGF or whatever.
No es exactamente la sintaxis normal de las opciones de Unix, porque aceptará opciones de parámetros de línea de comando que no sean opciones, como en " myprog -i foo bar -q
", pero puedo vivir con eso. (Algunas personas, como los desarrolladores de Subversion, prefieren esto. A veces yo también).
Una opción que está presente o ausente no se puede implementar mucho más simplemente que la anterior. (Una asignación, una llamada a función, un efecto secundario). ¿Existe una manera igualmente simple de tratar con las opciones que toman un parámetro, como " -f
nombre de archivo "?
EDITAR:
Un punto que no mencioné antes, porque no me quedó claro hasta que el autor de Trollop mencionó que la biblioteca encajaba "en un archivo de [800 líneas]", es que estoy buscando no solo limpiar sintaxis, pero para una técnica que tiene las siguientes características:
La totalidad del código se puede incluir en el archivo de secuencia de comandos (sin abrumar el propio script, que puede ser solo un par de docenas de líneas), de modo que uno puede colocar un solo archivo en un directorio
bin
en cualquier sistema con un estándar Ruby 1.8. [5-7] instalación y úselo. Si no puede escribir un script de Ruby que no requiere instrucciones y donde el código para analizar un par de opciones está por debajo de una docena de líneas, usted no cumple con este requisito.El código es pequeño y lo suficientemente simple como para que uno pueda recordar lo suficiente como para escribir directamente el código que hará el truco, en lugar de cortar y pegar desde otro lugar. Piense en la situación en la que se encuentra en la consola de un servidor cortafuegos sin acceso a Internet, y desea unir un guión rápido para que lo use un cliente. No sé ustedes, pero (además de no cumplir con el requisito anterior) memorizar incluso las 45 líneas de microoptimples simplificadas no es algo que me interese.
¿Has considerado Thor por wycats? Creo que es mucho más limpio que optparse. Si ya tiene un guión escrito, podría ser algo más de trabajo formatearlo o refactorizarlo para thor, pero sí hace que las opciones de manejo sean muy simples.
Aquí está el fragmento de ejemplo del archivo README:
class MyApp < Thor # [1]
map "-L" => :list # [2]
desc "install APP_NAME", "install one of the available apps" # [3]
method_options :force => :boolean, :alias => :optional # [4]
def install(name)
user_alias = options[:alias]
if options.force?
# do something
end
# ... other code ...
end
desc "list [SEARCH]", "list all of the available apps, limited by SEARCH"
def list(search = "")
# list everything
end
end
Thor mapea automáticamente los comandos como tal:
app install myname --force
Eso se convierte en:
MyApp.new.install("myname")
# with {''force'' => true} as options hash
- Heredar de Thor para convertir una clase en un asignador de opciones
- Asigne identificadores no válidos adicionales a métodos específicos. En este caso, convertir -L a: list
- Describe el método inmediatamente debajo. El primer parámetro es la información de uso, y el segundo parámetro es la descripción.
- Proporcione cualquier opción adicional. Estos serán distribuidos desde - y - params. En este caso, se agrega una opción --force and af.
Aparentemente @WilliamMorgan y yo pensamos igual. Acabo de lanzar anoche a Github lo que ahora veo es una biblioteca similar a Trollop (¿con nombre cómo?) Después de haber hecho una búsqueda de OptionParser en Github, ver Switches
Hay algunas diferencias, pero la filosofía es la misma. Una diferencia obvia es que Switches depende de OptionParser.
Como autor de Trollop , no puedo CREER las cosas que las personas piensan que son razonables en un analizador de opciones. Seriamente. Alucina la mente.
¿Por qué debería tener que hacer un módulo que amplíe algún otro módulo para analizar las opciones? ¿Por qué debería tener que subclasificar algo? ¿Por qué debería tener que suscribirme a algún "marco" solo para analizar la línea de comando?
Aquí está la versión Trollop de lo anterior:
opts = Trollop::options do
opt :quiet, "Use minimal output", :short => ''q''
opt :interactive, "Be interactive"
opt :filename, "File to process", :type => String
end
Y eso es. opts
ahora es un hash con claves :quiet
:interactive
y :filename
. Puedes hacer lo que quieras con eso. Y obtienes una hermosa página de ayuda, formateada para ajustarse al ancho de tu pantalla, nombres de argumentos cortos automáticos, verificación de tipos ... todo lo que necesitas.
Es un archivo, por lo que puede soltarlo en su directorio lib / si no desea una dependencia formal. Tiene un DSL mínimo que es fácil de recoger.
LOC por opción personas. Importa.
Comparto tu disgusto por require ''getopts''
, principalmente debido a la maravilla que es OptionParser
:
% cat temp.rb
require ''optparse''
OptionParser.new do |o|
o.on(''-d'') { |b| $quiet = b }
o.on(''-i'') { |b| $interactive = b }
o.on(''-f FILENAME'') { |filename| $filename = filename }
o.on(''-h'') { puts o; exit }
o.parse!
end
p :quiet => $quiet, :interactive => $interactive, :filename => $filename
% ruby temp.rb
{:interactive=>nil, :filename=>nil, :quiet=>nil}
% ruby temp.rb -h
Usage: temp [options]
-d
-i
-f FILENAME
-h
% ruby temp.rb -d
{:interactive=>nil, :filename=>nil, :quiet=>true}
% ruby temp.rb -i
{:interactive=>true, :filename=>nil, :quiet=>nil}
% ruby temp.rb -di
{:interactive=>true, :filename=>nil, :quiet=>true}
% ruby temp.rb -dif apelad
{:interactive=>true, :filename=>"apelad", :quiet=>true}
% ruby temp.rb -f apelad -i
{:interactive=>true, :filename=>"apelad", :quiet=>nil}
Dado que nadie parecía mencionarlo, y el título se refiere al análisis de línea de comandos barato , ¿por qué no dejar que el intérprete de rubíes haga el trabajo por usted? Si pasas el modificador -s
(en tu shebang, por ejemplo), obtienes conmutadores simples de suciedad de forma gratuita, asignados a variables globales de una sola letra. Aquí está su ejemplo usando ese interruptor:
#!/usr/bin/env ruby -s
puts "#$0: Quiet=#$q Interactive=#$i, ARGV=#{ARGV.inspect}"
Y aquí está la salida cuando ./test
eso como ./test
y chmod it +x
:
$ ./test
./test: Quiet= Interactive=, ARGV=[]
$ ./test -q foo
./test: Quiet=true Interactive=, ARGV=["foo"]
$ ./test -q -i foo bar baz
./test: Quiet=true Interactive=true, ARGV=["foo", "bar", "baz"]
$ ./test -q=very foo
./test: Quiet=very Interactive=, ARGV=["foo"]
Ver ruby -h
para más detalles. :)
Eso debe ser tan barato como sea posible. Levantará un NameError si intentas un cambio como -:
entonces hay algo de validación allí. Por supuesto, no puede tener ningún modificador después de un argumento que no sea de cambio, pero si necesita algo sofisticado, realmente debería usar al menos OptionParser. De hecho, lo único que me molesta de esta técnica es que recibirás una advertencia (si los has habilitado) al acceder a una variable global no configurada, pero sigue falsey, por lo que funciona bien para herramientas desechables y rápidas guiones.
Una advertencia ( como señaló FelipeC en los comentarios ) es que su caparazón podría no ser compatible con el shebang de 3 tokens; es posible que necesite reemplazar /usr/bin/env ruby -w
con la ruta real a su ruby (como /usr/local/bin/ruby -w
), o ejecutarlo desde un script envoltorio, o algo así.
Entiendo totalmente por qué quieres evitar optparse: puede ser demasiado. Pero hay algunas soluciones mucho más "livianas" (en comparación con OptParse) que se presentan como bibliotecas, pero son lo suficientemente simples como para hacer que la instalación de una única gema valga la pena.
Por ejemplo, mira este ejemplo de OptiFlag . Solo unas líneas para el procesamiento. Un ejemplo ligeramente truncado adaptado a su caso:
require ''optiflag''
module Whatever extend OptiFlagSet
flag "f"
and_process!
end
ARGV.flags.f # => .. whatever ..
También hay toneladas de ejemplos personalizados . Recuerdo haber usado otro que era incluso más fácil, pero por ahora me he escapado, pero volveré y añadiré un comentario aquí si lo encuentro.
Esta es la técnica estándar que suelo usar:
#!/usr/bin/env ruby
def usage(s)
$stderr.puts(s)
$stderr.puts("Usage: #{File.basename($0)}: [-l <logfile] [-q] file ...")
exit(2)
end
$quiet = false
$logfile = nil
loop { case ARGV[0]
when ''-q'' then ARGV.shift; $quiet = true
when ''-l'' then ARGV.shift; $logfile = ARGV.shift
when /^-/ then usage("Unknown option: #{ARGV[0].inspect}")
else break
end; }
# Program carries on here.
puts("quiet: #{$quiet} logfile: #{$logfile.inspect} args: #{ARGV.inspect}")
Este es mi analizador favorito de opciones rápidas y sucias:
case ARGV.join
when /-h/
puts "help message"
exit
when /-opt1/
puts "running opt1"
end
Las opciones son expresiones regulares, por lo que "-h" también coincidiría con "--help".
Legible, fácil de recordar, sin biblioteca externa y código mínimo.
Esto es lo que uso para args realmente, realmente baratos:
def main
ARGV.each { |a| eval a }
end
main
así que si ejecuta el nombre de programname foo bar
llama a foo y luego barra. Es útil para scripts desechables.
Esto es muy similar a la respuesta aceptada, pero usando ARGV.delete_if
que es lo que uso en mi analizador simple . La única diferencia real es que las opciones con argumentos deben estar juntas (por ejemplo, -l=file
).
def usage
"usage: #{File.basename($0)}: [-l=<logfile>] [-q] file ..."
end
$quiet = false
$logfile = nil
ARGV.delete_if do |cur|
next false if cur[0] != ''-''
case cur
when ''-q''
$quiet = true
when /^-l=(.+)$/
$logfile = $1
else
$stderr.puts "Unknown option: #{cur}"
$stderr.puts usage
exit 1
end
end
puts "quiet: #{$quiet} logfile: #{$logfile.inspect} args: #{ARGV.inspect}"
Estoy desarrollando mi propia gema de analizador de opciones llamada Acclaim .
Lo escribí porque quería crear interfaces de línea de comando estilo git y poder separar limpiamente la funcionalidad de cada comando en clases separadas, pero también se puede usar sin todo el marco de comandos:
(options = []) << Acclaim::Option.new(:verbose, ''-v'', ''--verbose'')
values = Acclaim::Option::Parser.new(ARGV, options).parse!
puts ''Verbose.'' if values.verbose?
Aún no hay una versión estable, pero ya he implementado algunas características como:
- analizador de opciones personalizadas
- análisis flexible de los argumentos de la opción que permite tanto el mínimo como el opcional
- soporte para muchos estilos de opciones
- reemplazar, agregar o aumentar en varias instancias de la misma opción
- manejadores de opciones personalizadas
- manejadores de tipo personalizado
- controladores predefinidos para las clases de biblioteca estándar común
Hay un gran énfasis en los comandos, por lo que puede ser un poco pesado para el análisis de línea de comandos simple, pero funciona bien y lo he estado usando en todos mis proyectos. Si está interesado en el aspecto de la interfaz de comando, consulte la página GitHub del proyecto para obtener más información y ejemplos.
Puedes probar algo como:
if( ARGV.include( ''-f'' ) )
file = ARGV[ARGV.indexof( ''-f'' ) + 1 )]
ARGV.delete(''-f'')
ARGV.delete(file)
end
Si desea un analizador de línea de comando simple para comandos de clave / valor sin el uso de gemas:
Pero esto solo funciona si siempre tienes pares clave / valor.
# example
# script.rb -u username -p mypass
# check if there are even set of params given
if ARGV.count.odd?
puts ''invalid number of arguments''
exit 1
end
# holds key/value pair of cl params {key1 => value1, key2 => valye2, ...}
opts = {}
(ARGV.count/2).times do |i|
k,v = ARGV.shift(2)
opts[k] = v # create k/v pair
end
# set defaults if no params are given
opts[''-u''] ||= ''root''
# example use of opts
puts "username:#{opts[''-u'']} password:#{opts[''-p'']}"
Si no necesita ninguna verificación , puede usar:
opts = {}
(ARGV.count/2).times do |i|
k,v = ARGV.shift(2)
opts[k] = v # create k/v pair
end
Supongamos que un comando tiene como máximo una acción y un número arbitrario de opciones como esta:
cmd.rb
cmd.rb action
cmd.rb action -a -b ...
cmd.rb action -ab ...
El análisis sin validación puede ser así:
ACTION = ARGV.shift
OPTIONS = ARGV.join.tr(''-'', '''')
if ACTION == ''***''
...
if OPTIONS.include? ''*''
...
end
...
end
Voy a compartir mi propio analizador de opciones simple en el que he estado trabajando durante un tiempo. Es meramente 74 líneas de código, y hace lo básico de lo que hace el analizador de opciones interno de Git. Tomé OptionParser como inspiración, y también de Git.
https://gist.github.com/felipec/6772110
Se parece a esto:
opts = ParseOpt.new
opts.usage = "git foo"
opts.on("b", "bool", help: "Boolean") do |v|
$bool = v
end
opts.on("s", "string", help: "String") do |v|
$str = v
end
opts.on("n", "number", help: "Number") do |v|
$num = v.to_i
end
opts.parse
micro-optparse para cubrir esta necesidad obvia de un analizador de opciones corto pero fácil de usar. Tiene una sintaxis similar a Trollop y tiene 70 líneas cortas. Si no necesita validaciones y puede hacerlo sin líneas vacías, puede cortarlo a 45 líneas. Creo que eso es exactamente lo que estabas buscando.
Ejemplo corto:
options = Parser.new do |p|
p.version = "fancy script version 1.0"
p.option :verbose, "turn on verbose mode"
p.option :number_of_chairs, "defines how many chairs are in the classroom", :default => 1
p.option :room_number, "select room number", :default => 2, :value_in_set => [1,2,3,4]
end.process!
Se imprimirá la secuencia de comandos con -h
o --help
Usage: micro-optparse-example [options]
-v, --[no-]verbose turn on verbose mode
-n, --number-of-chairs 1 defines how many chairs are in the classroom
-r, --room-number 2 select room number
-h, --help Show this message
-V, --version Print version
Comprueba si la entrada es del mismo tipo que el valor predeterminado, genera accesos cortos y largos, imprime mensajes descriptivos de error si se dan argumentos no válidos y más.
Comparé varios analizador de opciones usando cada opción-analizador para el problema que tenía. Puede usar estos ejemplos y mi resumen para tomar una decisión informativa. Siéntase libre de agregar más implementaciones a la lista. :)
Trollop es bastante barato.
EasyOptions no requiere ningún código de análisis de opciones. Simplemente escriba el texto de ayuda, requiera, listo.
## Options:
## -i, --interactive Interactive mode
## -q, --quiet Silent mode
require ''easyoptions''
unless EasyOptions.options[:quiet]
puts ''Interactive mode enabled'' if EasyOptions.options[:interactive]
EasyOptions.arguments.each { |item| puts "Argument: #{item}" }
end
https://github.com/soveran/clap
other_args = Clap.run ARGV,
"-s" => lambda { |s| switch = s },
"-o" => lambda { other = true }
46LOC (en 1.0.0), no hay dependencia en el analizador de opciones externo. Obtiene el trabajo hecho. Probablemente no sea tan completo como otros, pero es 46LOC.
Si revisas el código, puedes duplicar con bastante facilidad la técnica subyacente: asigna lambdas y usa el arity para asegurarte de que el número correcto de argumentos sigue el indicador si realmente no quieres una biblioteca externa.
Sencillo. Barato.