Para la mayoría de los casos, no necesita un analizador externo. La coincidencia de patrones de Scala permite consumir args en un estilo funcional. Por ejemplo:
object MmlAlnApp {
val usage = """
Usage: mmlaln [--min-size num] [--max-size num] filename
"""
def main(args: Array[String]) {
if (args.length == 0) println(usage)
val arglist = args.toList
type OptionMap = Map[Symbol, Any]
def nextOption(map : OptionMap, list: List[String]) : OptionMap = {
def isSwitch(s : String) = (s(0) == '-')
list match {
case Nil => map
case "--max-size" :: value :: tail =>
nextOption(map ++ Map('maxsize -> value.toInt), tail)
case "--min-size" :: value :: tail =>
nextOption(map ++ Map('minsize -> value.toInt), tail)
case string :: opt2 :: tail if isSwitch(opt2) =>
nextOption(map ++ Map('infile -> string), list.tail)
case string :: Nil => nextOption(map ++ Map('infile -> string), list.tail)
case option :: tail => println("Unknown option "+option)
exit(1)
}
}
val options = nextOption(Map(),arglist)
println(options)
}
}
imprimirá, por ejemplo:
Map('infile -> test/data/paml-aln1.phy, 'maxsize -> 4, 'minsize -> 2)
Esta versión solo toma un infile. Fácil de mejorar (mediante el uso de una lista).
Tenga en cuenta también que este enfoque permite la concatenación de múltiples argumentos de línea de comandos, ¡incluso más de dos!
nextOption
No es un buen nombre para la función. Es una función que devuelve un mapa; el hecho de que sea recursivo es un detalle de implementación. Es como escribir unamax
función para una colección y llamarlanextMax
simplemente porque la escribió con recursividad explícita. ¿Por qué no solo llamarlooptionMap
?listToOptionMap(lst:List[String])
con la funciónnextOption
definida dentro de eso, con una línea final que digareturn nextOption(Map(), lst)
. Dicho esto, tengo que confesar que he hecho atajos mucho más atroces en mi tiempo que el de esta respuesta.exit(1)
puede ser necesariosys.exit(1)
file
parámetros:case string :: tail => { if (isSwitch(string)) { println("Unknown option: " + string) sys.exit(1) } else nextOption(map ++ Map('files -> (string :: map('files).asInstanceOf[List[String]])), tail)
. El mapa también necesita un valor predeterminado deNil
, es decirval options = nextOption(Map() withDefaultValue Nil, args.toList)
. Lo que no me gusta es tener que recurrirasInstanceOf
, debido a que losOptionMap
valores son de tipoAny
. ¿Hay una mejor solución?scopt / scopt
Lo anterior genera el siguiente texto de uso:
Esto es lo que uso actualmente. Uso limpio sin demasiado equipaje. (Descargo de responsabilidad: ahora mantengo este proyecto)
fuente
Me di cuenta de que la pregunta se hizo hace algún tiempo, pero pensé que podría ayudar a algunas personas, que están buscando en Google (como yo), y accedí a esta página.
La vieira también parece bastante prometedora.
Características (cita de la página de github vinculada):
Y algún código de ejemplo (también de esa página de Github):
fuente
(x, c) => c.copy(xyz = x)
en alcanceMe gusta deslizarme sobre argumentos para configuraciones relativamente simples.
fuente
args.sliding(2, 2)
?var port = 0
?Interfaz de línea de comando Scala Toolkit (CLIST)
¡Aquí está el mío también! (aunque un poco tarde en el juego)
https://github.com/backuity/clist
Por el contrario
scopt
, es completamente mutable ... ¡pero espera! Eso nos da una sintaxis bastante buena:Y una forma simple de ejecutarlo:
Puede hacer mucho más, por supuesto (comandos múltiples, muchas opciones de configuración, ...) y no tiene dependencia.
Terminaré con un tipo de característica distintiva, el uso predeterminado (a menudo descuidado para los comandos múltiples):
fuente
Password
,Hex
, ...), entonces se puede aprovechar esto.Este es en gran medida un clon descarado de mi respuesta a la pregunta de Java sobre el mismo tema . Resulta que JewelCLI es compatible con Scala, ya que no requiere métodos de estilo JavaBean para obtener nombres automáticos de argumentos.
JewelCLI es una biblioteca Java compatible con Scala para el análisis de la línea de comandos que produce un código limpio . Utiliza interfaces proxy configuradas con anotaciones para crear dinámicamente una API de tipo seguro para los parámetros de la línea de comandos.
Un ejemplo de interfaz de parámetros
Person.scala
:Un ejemplo de uso de la interfaz de parámetros
Hello.scala
:Guarde copias de los archivos anteriores en un solo directorio y descargue JewelCLI 0.6 JAR también en ese directorio.
Compile y ejecute el ejemplo en Bash en Linux / Mac OS X / etc .:
Compile y ejecute el ejemplo en el símbolo del sistema de Windows:
Ejecutar el ejemplo debería producir el siguiente resultado:
fuente
Cómo analizar parámetros sin una dependencia externa. Gran pregunta! Te puede interesar picocli .
Picocli está específicamente diseñado para resolver el problema planteado en la pregunta: es un marco de análisis de línea de comando en un solo archivo, por lo que puede incluirlo en forma de código fuente . Esto permite a los usuarios ejecutar aplicaciones basadas en picocli sin requerir picocli como dependencia externa .
Funciona anotando campos para que escriba muy poco código. Sumario rápido:
<command> -xvfInputFile
tan bien como<command> -x -v -f InputFile
)"1..*"
,"3..5"
El mensaje de ayuda de uso es fácil de personalizar con anotaciones (sin programación). Por ejemplo:
( fuente )
No pude resistirme a agregar una captura de pantalla más para mostrar qué tipo de mensajes de ayuda de uso son posibles. La ayuda de uso es la cara de su aplicación, ¡así que sea creativo y diviértase!
Descargo de responsabilidad: creé picocli. Comentarios o preguntas muy bienvenidos. Está escrito en Java, pero avíseme si hay algún problema al usarlo en Scala e intentaré solucionarlo.
fuente
Soy del mundo Java, me gusta args4j porque su especificación simple es más legible (gracias a las anotaciones) y produce una salida con un formato agradable.
Aquí está mi fragmento de ejemplo:
Especificación
Analizar gramaticalmente
Sobre argumentos inválidos
fuente
scala-optparse-aplicativo
Creo que scala-optparse-Applicative es la biblioteca de analizador de línea de comandos más funcional de Scala.
https://github.com/bmjames/scala-optparse-applicative
fuente
examples
código de pruebaTambién hay JCommander (descargo de responsabilidad: lo creé):
fuente
Me gustó el enfoque slide () de joslinm simplemente no los vars mutables;) Así que aquí hay una forma inmutable de ese enfoque:
fuente
Acabo de encontrar una extensa biblioteca de análisis de línea de comandos en el paquete scala.tools.cmd de scalac.
Ver http://www.assembla.com/code/scala-eclipse-toolchain/git/nodes/src/compiler/scala/tools/cmd?rev=f59940622e32384b1e08939effd24e924a8ba8db
fuente
Intenté generalizar la solución de @ pjotrp tomando una lista de los símbolos de teclas de posición requeridos, un mapa de bandera -> símbolo de tecla y opciones predeterminadas:
fuente
-f|--flags
. Eche un vistazo a gist.github.com/DavidGamba/b3287d40b019e498982c y no dude en actualizar la respuesta si lo desea. Probablemente haré cada mapa y opción para que solo pueda pasar lo que necesitará con argumentos con nombre.Basé mi enfoque en la respuesta principal (de dave4420) e intenté mejorarlo haciéndolo más general.
Devuelve uno
Map[String,String]
de todos los parámetros de la línea de comandos. Puede consultar esto para los parámetros específicos que desee (por ejemplo, usar.contains
) o convertir los valores en los tipos que desee (por ejemplo, usartoInt
).Ejemplo:
Da:
fuente
otra biblioteca: scarg
fuente
Aquí hay un analizador de línea de comando scala que es fácil de usar. Formatea automáticamente el texto de ayuda y convierte los argumentos de cambio al tipo deseado. Se admiten conmutadores de estilo de GNU cortos y largos de POSIX. Admite conmutadores con argumentos obligatorios, argumentos opcionales y argumentos de valores múltiples. Incluso puede especificar la lista finita de valores aceptables para un interruptor en particular. Los nombres largos de los interruptores se pueden abreviar en la línea de comandos para mayor comodidad. Similar al analizador de opciones en la biblioteca estándar de Ruby.
fuente
Nunca me han gustado los analizadores de rubíes como opción. La mayoría de los desarrolladores que los usaron nunca escriben una página de manual adecuada para sus scripts y terminan con opciones largas de páginas que no están organizadas de manera adecuada debido a su analizador.
Siempre he preferido la forma en que Perl hace las cosas con Perl's Getopt :: Long .
Estoy trabajando en una implementación scala de la misma. La primera API se parece a esto:
Entonces llamando
script
así:Imprimiría:
Y volver:
El proyecto está alojado en github scala-getoptions .
fuente
Acabo de crear mi enumeración simple
Entiendo que la solución tiene dos fallas principales que pueden distraerlo: elimina la libertad (es decir, la dependencia de otras bibliotecas, que valora tanto) y la redundancia (el principio DRY, escribe el nombre de la opción solo una vez, como programa Scala variable y eliminarlo por segunda vez escrito como texto de línea de comando).
fuente
Sugeriría usar http://docopt.org/ . Hay un puerto scala, pero la implementación de Java https://github.com/docopt/docopt.java funciona bien y parece estar mejor mantenida. Aquí hay un ejemplo:
fuente
Esto es lo que cociné. Devuelve una tupla de un mapa y una lista. La lista es para la entrada, como los nombres de los archivos de entrada. El mapa es para interruptores / opciones.
volverá
Los interruptores pueden ser "--t", que x se establecerá en verdadero, o "--x 10", que x se establecerá en "10". Todo lo demás terminará en la lista.
fuente
Me gusta el aspecto limpio de este código ... extraído de una discusión aquí: http://www.scala-lang.org/old/node/4380
fuente
Como todos publicaron su propia solución aquí es mía, porque quería algo más fácil de escribir para el usuario: https://gist.github.com/gwenzek/78355526e476e08bb34d
La esencia contiene un archivo de código, más un archivo de prueba y un breve ejemplo copiado aquí:
No hay opciones sofisticadas para forzar que una variable esté dentro de ciertos límites, porque no creo que el analizador sea el mejor lugar para hacerlo.
Nota: puede tener tanto alias como desee para una variable dada.
fuente
Me voy a amontonar. Resolví esto con una simple línea de código. Mis argumentos de línea de comando se ven así:
Esto crea una matriz a través de la funcionalidad de línea de comando nativa de Scala (desde la aplicación o un método principal):
Entonces puedo usar esta línea para analizar la matriz de argumentos predeterminada:
Lo que crea un mapa con nombres asociados con los valores de la línea de comando:
Entonces puedo acceder a los valores de los parámetros con nombre en mi código y el orden en que aparecen en la línea de comandos ya no es relevante. Me doy cuenta de que esto es bastante simple y no tiene todas las funciones avanzadas mencionadas anteriormente, pero parece ser suficiente en la mayoría de los casos, solo necesita una línea de código y no involucra dependencias externas.
fuente
Aquí está el mío 1-liner
Deja caer 3 argumentos obligatorios y da las opciones. Los enteros se especifican como una notoria
-Xmx<size>
opción de Java, conjuntamente con el prefijo. Puede analizar binarios y enteros tan simples comoNo es necesario importar nada.
fuente
Un trazo rápido y sucio del pobre para analizar pares clave = valor:
fuente
freecli
Esto generará el siguiente uso:
Uso
fuente