design patterns - prototipos - ¿Cuál es el patrón de diseño para procesar argumentos de línea de comando?
singleton java (16)
¿Qué tal el patrón de intérprete? http://www.dofactory.com/net/interpreter-design-pattern
Si está escribiendo un programa que es ejecutable desde la línea de comandos, a menudo desea ofrecer al usuario varias opciones o indicadores, junto con posiblemente más de un argumento. He tropezado a través de esto muchas veces, pero ¿hay algún tipo de patrón de diseño para pasar por args y girar las funciones apropiadas?
Considerar:
myprogram -f filename -d directory -r regex
¿Cómo se organiza el código después de recuperar los argumentos utilizando los integrables para su idioma? (Las respuestas específicas al idioma son bienvenidas, si eso ayuda a articular una respuesta)
Algunos comentarios sobre esto ...
En primer lugar, si bien no existen patrones en sí mismos, escribir un analizador es esencialmente un ejercicio mecánico, ya que dada una gramática, se puede generar fácilmente un analizador sintáctico. Herramientas como Bison y ANTLR vienen a la mente.
Dicho esto, los generadores de analizadores generalmente son excesivos para la línea de comando. Entonces, el patrón habitual es escribir uno usted mismo (como han demostrado otros) un par de veces hasta que se canse de lidiar con el tedioso detalle y encuentre una biblioteca que lo haga por usted.
Escribí uno para C ++ que ahorra un montón de esfuerzo que imparte getopt y hace un buen uso de las plantillas: TCLAP
Bueno, es una publicación anterior, pero me gustaría contribuir. La pregunta estaba dirigida a la elección de los patrones de diseño; sin embargo, pude ver mucha discusión sobre qué biblioteca usar. He revisado el enlace de Microsoft según Lindsay, que habla sobre el patrón de diseño de la plantilla a usar.
Sin embargo, no estoy convencido con la publicación. La intención del patrón de la plantilla es definir una plantilla que será implementada por varias otras clases para tener un comportamiento uniforme. No creo que el análisis de la línea de comandos encaje.
Prefiero ir con el patrón de diseño "Comando". Este patrón es el más adecuado para las opciones de menú.
http://www.blackwasp.co.uk/Command.aspx
entonces en su caso, -f, -d y -r todo se convierte en comandos que tienen un receptor común o separado definido. De esa forma se pueden definir más receptores en el futuro. El siguiente paso será encadenar estas responsabilidades de comandos, en caso de que se requiera una cadena de procesamiento. Por lo que elegiría.
http://www.blackwasp.co.uk/ChainOfResponsibility.aspx
Supongo que la combinación de estos dos es mejor para organizar el código para el procesamiento de línea de comandos o cualquier enfoque basado en menús.
Creo que la siguiente respuesta es más acorde con lo que estás buscando:
Debería ver la aplicación del patrón de plantilla (Método de plantilla en "Patrones de diseño" [Gamma, el al])
En resumen, el proceso general se ve así:
If the arguments to the program are valid then
Do necessary pre-processing
For every line in the input
Do necessary input processing
Do necessary post-processing
Otherwise
Show the user a friendly usage message
En resumen, implemente una clase ConsoleEngineBase que tenga métodos para:
PreProcess()
ProcessLine()
PostProcess()
Usage()
Main()
A continuación, cree un chasis que ejemplifique una instancia de ConsoleEngine () y envíe el mensaje Main () para iniciarlo.
Para ver un buen ejemplo de cómo aplicar esto a una consola o un programa de línea de comando, consulte el siguiente enlace: http://msdn.microsoft.com/en-us/magazine/cc164014.aspx
El ejemplo está en C #, pero las ideas se implementan fácilmente en cualquier otro entorno.
Consideraría el GetOpt () simplemente como la parte que encaja en el manejo de argumentos (preprocesamiento).
Espero que esto ayude.
El diseño estándar generalmente sigue lo que hace getopt, hay librerías getopt para muchos idiomas, .NET, python, C, Perl, PHP, etc.
El diseño básico es tener un analizador de línea de comando que devuelve parte por parte los argumentos pasados para verificarse en un bucle.
This artículo lo analiza con más detalle.
Estoy escribiendo sobre la respuesta ANTLR por mes5k. Este enlace a Codeproject es para un artículo que analiza ANLTR y utiliza el patrón de visitas para implementar las acciones que desea que tome su aplicación. Está bien escrito y vale la pena revisarlo.
Getopt es el único camino a seguir.
La biblioteca boost::program_options es agradable si estás en C ++ y tienes el lujo de usar Boost.
No estoy tan interesado en las bibliotecas, aunque eso definitivamente es útil. Buscaba más un "pseudo código" que ilustra el procesamiento de, por ejemplo, el conjunto de banderas promedio y un grupo de argumentos más largos.
No mencionó el idioma, pero para Java nos gustó la CLI de Apache Commons . Para C / C ++, getopt.
No mencionas un idioma para esto, pero si buscas un envoltorio Objective-C realmente bueno alrededor de getopt entonces el framework DDCLI de Dave Dribin es realmente agradable.
No sé de ningún "patrón" documentado para el procesamiento.
Creo que una de las bibliotecas / API más antiguas para manejar argumentos es getopt. Google "getopt" muestra muchas páginas man y enlaces a implementaciones.
En general, tengo un servicio de preferencias o configuraciones en mi aplicación que el procesador de argumentos sabe cómo comunicarse. Los argumentos se traducen en algo en este servicio que la aplicación luego consulta. Esto podría ser tan simple como un diccionario de configuraciones (como una configuración de cadena llamada "nombre de archivo").
Prefiero opciones como "-t text" y "-i 44"; No me gusta "-fname" o "--very-long-argument = some_value".
Y "-?", "-h" y "/ h" producen una pantalla de ayuda.
Así es como se ve mi código:
int main (int argc, char *argv[])
{ int i;
char *Arg;
int ParamX, ParamY;
char *Text, *Primary;
// Initialize...
ParamX = 1;
ParamY = 0;
Text = NULL;
Primary = NULL;
// For each argument...
for (i = 0; i < argc; i++)
{
// Get the next argument and see what it is
Arg = argv[i];
switch (Arg[0])
{
case ''-'':
case ''/'':
// It''s an argument; which one?
switch (Arg[1])
{
case ''?'':
case ''h'':
case ''H'':
// A cry for help
printf ("Usage: whatever.../n/n");
return (0);
break;
case ''t'':
case ''T'':
// Param T requires a value; is it there?
i++;
if (i >= argc)
{
printf ("Error: missing value after ''%s''./n/n", Arg);
return (1);
}
// Just remember this
Text = Arg;
break;
case ''x'':
case ''X'':
// Param X requires a value; is it there?
i++;
if (i >= argc)
{
printf ("Error: missing value after ''%s''./n/n", Arg);
return (1);
}
// The value is there; get it and convert it to an int (1..10)
Arg = argv[i];
ParamX = atoi (Arg);
if ((ParamX == 0) || (ParamX > 10))
{
printf ("Error: invalid value for ''%s''; must be between 1 and 10./n/n", Arg);
return (1);
}
break;
case ''y'':
case ''Y'':
// Param Y doesn''t expect a value after it
ParamY = 1;
break;
default:
// Unexpected argument
printf ("Error: unexpected parameter ''%s''; type ''command -?'' for help./n/n", Arg);
return (1);
break;
}
break;
default:
// It''s not a switch that begins with ''-'' or ''/'', so it''s the primary option
Primary = Arg;
break;
}
}
// Done
return (0);
}
Suponiendo que tiene un objeto "config" que desea configurar con los indicadores y un analizador de línea de comando adecuado que se encarga de analizar la línea de comando y suministrar un flujo constante de las opciones, aquí va un bloque de pseudocódigo
while (current_argument = cli_parser_next()) {
switch(current_argument) {
case "f": //Parser strips the dashes
case "force":
config->force = true;
break;
case "d":
case "delete":
config->delete = true;
break;
//So on and so forth
default:
printUsage();
exit;
}
}
Utilizo Getopts::std y Getopts::long en Perl y también la función Getopt en C. Esto estandariza el análisis sintáctico y el formato de los parámetros. Otros idiomas tienen diferentes mecanismos para manejarlos.
Espero que esto ayude
Yo recomendaría usar una biblioteca de procesador de línea de comando. Un tipo ruso creó uno decente, pero hay toneladas de ellos por ahí. Le ahorrará algo de tiempo para que pueda concentrarse en el propósito de su aplicación en lugar de analizar los interruptores de línea de comando.