Pule tu aplicación de CLI
Mejora el HelpCommand para proporcionar información más detallada y agrega un argumento onOutput para un manejo de salida flexible.
En este capítulo, darás los toques finales al paquete command_runner.
Refinarás el HelpCommand para proporcionar información de uso más detallada y
agregarás un argumento onOutput para un manejo de salida más flexible.
Esto finaliza el paquete CommandRunner y lo prepara para
su uso en escenarios más complejos.
Qué lograrás
Prerrequisitos
#Antes de comenzar este capítulo, asegúrate de:
- Haber completado el Capítulo 7 y tener un
entorno de desarrollo de Dart en funcionamiento con el proyecto
dartpedia. - Estar familiarizado con conceptos básicos de programación como variables, funciones y flujo de control.
- Entender los conceptos de paquetes y librerías en Dart.
- Estar familiarizado con los principios de programación orientada a objetos como la herencia y las clases abstractas.
Tareas
#Pulirás el paquete command_runner para
hacerlo más robusto y fácil de usar.
Tarea 1 Mejorar la salida de HelpCommand
#
Mejora el HelpCommand para proporcionar información de uso más detallada,
incluyendo opciones y sus descripciones.
Esto facilitará a los usuarios
entender cómo usar tu aplicación de CLI.
Abre el archivo
command_runner/lib/src/help_command.dart.-
Agrega imports para
console.dartyexceptions.darten la parte superior del archivo. Los necesitas para usar las extensiones de color y para lanzar unaArgumentException.dartimport 'dart:async'; import 'package:command_runner/command_runner.dart'; import 'console.dart'; import 'exceptions.dart'; -
Reemplaza el método
runexistente con el siguiente. Esta nueva versión utiliza unStringBufferpara construir eficientemente la cadena de ayuda e incluye la lógica para manejar la salida detallada (verbose).dart@override FutureOr<String> run(ArgResults args) async { final buffer = StringBuffer(); buffer.writeln(runner.usage.titleText); if (args.flag('verbose')) { for (var cmd in runner.commands) { buffer.write(_renderCommandVerbose(cmd)); } return buffer.toString(); } if (args.hasOption('command')) { var (:option, :input) = args.getOption('command'); var cmd = runner.commands.firstWhere( (command) => command.name == input, orElse: () { throw ArgumentException( 'Input $input is not a known command.', name, ); }, ); return _renderCommandVerbose(cmd); } // Verbose is false and no arg was passed in, so print basic usage. for (var command in runner.commands) { buffer.writeln(command.usage); } return buffer.toString(); }StringBufferes una clase de Dart que te permite construir cadenas de texto de manera eficiente. Tiene un mejor rendimiento que usar el operador+, especialmente al realizar muchas concatenaciones dentro de un bucle. -
Agrega el método de ayuda privado
_renderCommandVerbosea la claseHelpCommand. Este método da formato a la salida detallada para un solo comando.dartString _renderCommandVerbose(Command cmd) { final indent = ' ' * 10; final buffer = StringBuffer(); buffer.writeln(cmd.usage.instructionText); //abbr, name: description buffer.writeln('$indent ${cmd.help}'); if (cmd.valueHelp != null) { buffer.writeln( '$indent [Argument] Required? ${cmd.requiresArgument}, Type: ${cmd.valueHelp}, Default: ${cmd.defaultValue ?? 'none'}', ); } buffer.writeln('$indent Options:'); for (var option in cmd.options) { buffer.writeln('$indent ${option.usage}'); } return buffer.toString(); }
Tarea 2 Agregar un callback onOutput
#
A continuación, agrega un argumento onOutput a CommandRunner para
permitir un manejo de salida flexible.
Abre el archivo
command_runner/lib/src/command_runner_base.dart.-
Agrega el argumento
onOutputal constructor deCommandRunner, y agrega el miembroonOutputcorrespondiente a la clase.dartclass CommandRunner { CommandRunner({this.onOutput, this.onError}); /// If not null, this method is used to handle output. Useful if you want to /// execute code before the output is printed to the console, or if you /// want to do something other than print output the console. /// If null, the onInput method will [print] the output. FutureOr<void> Function(String)? onOutput; FutureOr<void> Function(Object)? onError; // ... rest of the class } -
Actualiza el método
runpara usar el argumentoonOutput.dartFuture<void> run(List<String> input) async { try { final ArgResults results = parse(input); if (results.command != null) { Object? output = await results.command!.run(results); if (onOutput != null) { await onOutput!(output.toString()); } else { print(output.toString()); } } } on Exception catch (exception) { if (onError != null) { onError!(exception); } else { rethrow; } } }Esto updates el método
runpara usar la funciónonOutputsi se proporciona; de lo contrario, se imprime en la consola de forma predeterminada.
Tarea 3 Usar el callback onOutput
#
Finalmente, actualiza tu aplicación principal para usar la nueva característica onOutput.
Abre el archivo
cli/bin/cli.dart.-
Actualiza la función
mainpara pasar la funciónonOutputaCommandRunner. También necesitarás agregar un import paraconsole.dartpara hacer disponible la funciónwrite.dartimport 'package:command_runner/command_runner.dart'; const version = '0.0.1'; void main(List<String> arguments) { var commandRunner = CommandRunner( onOutput: (String output) async { await write(output); }, onError: (Object error) { if (error is Error) { throw error; } if (error is Exception) { print(error); } }, )..addCommand(HelpCommand()); commandRunner.run(arguments); }
Tarea 4 Probar los cambios
#Prueba el HelpCommand mejorado y el callback onOutput.
Abre tu terminal y navega al directorio
cli.-
Ejecuta el comando
dart run bin/cli.dart help --verbose.Deberías ver información de uso detallada para el comando
help, impresa usando la función personalizadawrite.
Revisión
#Qué lograste
Aquí tienes un resumen de lo que construiste y aprendiste en esta lección.Usaste StringBuffer para construir cadenas de forma eficiente
Reemplazaste la concatenación de cadenas por un StringBuffer, lo cual puede ser más eficiente para construir cadenas en bucles. Métodos como
writeln() y write() añaden contenido, mientras que toString() produce la cadena final.
Mejoraste HelpCommand con salida detallada (verbose)
Mejoraste el sistema de ayuda para mostrar información de uso detallada que incluye opciones, valores predeterminados y descripciones. La bandera
--verbose y la opción --command dan control a los usuarios sobre el nivel de detalle.
Agregaste un argumento callback onOutput para un manejo flexible
Agregaste onOutput a CommandRunner, permitiendo a los consumidores de la librería personalizar cómo se muestra la salida. Este patrón hace que tu paquete sea más flexible y adaptable, permitiendo la impresión diferida, el registro (logging) o la redirección de la salida.
Cuestionario
#Pon a prueba tu comprensión
1 / 2StringBuffer class in Dart?Para almacenar una cadena de tamaño fijo.
No exactamente.
Las cadenas en Dart son inmutables y no tienen el concepto de tamaño fijo.
StringBuffersirve para un propósito diferente relacionado con la creación de cadenas.Para construir cadenas de manera eficiente añadiendo múltiples partes.
¡Correcto!
StringBufferproporciona una concatenación de cadenas eficiente al evitar la creación de objetos de cadena intermedios durante múltiples adiciones sucesivas.Para cifrar cadenas.
No exactamente.
El cifrado requiere librerías de criptografía especializadas.
StringBufferes una utilidad de propósito general, no está relacionada con la seguridad.Para comparar la igualdad de dos cadenas.
No exactamente.
La comparación de cadenas se hace usando
==ocompareTo().StringBuffersirve para un propósito diferente.
onOutput argument in the CommandRunner class allow you to do?Definir el nombre de un comando.
No exactamente.
Los nombres de los comandos se definen en el getter
namede la claseCommand.onOutputsirve para un propósito diferente.Especificar la entrada para un comando.
No exactamente.
La entrada proviene de los argumentos de línea de comandos pasados a
run(). El nombreonOutputsugiere que se trata de otra cosa.Establecer el mensaje de error para un comando.
No exactamente.
El manejo de errores tiene su propio mecanismo (
onError).onOutputes para un tipo diferente de resultado.Personalizar el manejo de salida de un comando.
¡Correcto!
onOutputte permite definir un comportamiento personalizado para la salida del comando, como formato, registro (logging) o escritura en diferentes destinos.
Siguiente lección
#En la siguiente lección, te prepararás para la parte de Wikipedia de la aplicación.
A menos que se indique lo contrario, la documentación de este sitio refleja Dart 3.12.2. Página actualizada por última vez el 17-06-2026. Ver fuente oreportar un problema.