Extiende tu aplicación con enums y extensiones
Mejora tus habilidades en Dart explorando características avanzadas como enums mejorados y extensiones. Mejora el formato y el color de la salida de tu aplicación, haciéndola más amigable para el usuario.
En este capítulo, explorarás características avanzadas de Dart que mejoran la experiencia de usuario de tu aplicación de línea de comandos. Aprenderás a usar enums mejorados para gestionar colores en la consola y extensiones para añadir nueva funcionalidad a tipos existentes, haciendo que tu aplicación sea más interactiva y visualmente atractiva.
Qué lograrás
Prerrequisitos
#Antes de comenzar este capítulo, asegúrate de:
- Haber completado el Capítulo 6 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.
- Tener una comprensión básica de conceptos de programación orientada a objetos como clases y enums.
Tareas
#Mejorarás la experiencia de usuario de tu aplicación de CLI de Dartpedia añadiendo color a la salida y mejorando el formato del texto.
Tarea 1: Mejorar el enum de colores de la consola
#Primero, añade color a la salida de la consola.
El enum ConsoleColor incluirá valores RGB y
métodos para aplicar colores al texto.
Crea el archivo
command_runner/lib/src/console.dart.-
Añade el siguiente código para definir el enum
ConsoleColor:command_runner/lib/src/console.dartdartimport 'dart:io'; const String ansiEscapeLiteral = '\x1B'; /// Splits strings on `\n` characters, then writes each line to the /// console. [duration] defines how many milliseconds there will be /// between each line print. Future<void> write(String text, {int duration = 50}) async { final List<String> lines = text.split('\n'); for (final String l in lines) { await _delayedPrint('$l \n', duration: duration); } } /// Prints line-by-line Future<void> _delayedPrint(String text, {int duration = 0}) async { return Future<void>.delayed( Duration(milliseconds: duration), () => stdout.write(text), ); } /// RGB formatted colors that are used to style input /// /// All colors from Dart's brand styleguide /// /// As a demo, only includes colors this program cares about. /// If you want to use more colors, add them here. enum ConsoleColor { /// Sky blue - #b8eafe lightBlue(184, 234, 254), /// Accent colors from Dart's brand guidelines /// Warm red - #F25D50 red(242, 93, 80), /// Light yellow - #F9F8C4 yellow(249, 248, 196), /// Light grey, good for text, #F8F9FA grey(240, 240, 240), /// white(255, 255, 255); const ConsoleColor(this.r, this.g, this.b); final int r; final int g; final int b; }Este enum define un conjunto de colores de consola con sus correspondientes valores RGB. Cada color es una instancia constante del enum
ConsoleColor. -
Añade métodos al enum
ConsoleColorpara aplicar colores al texto:command_runner/lib/src/console.dartdartenum ConsoleColor { // ... (existing enum values) const ConsoleColor(this.r, this.g, this.b); final int r; final int g; final int b; /// Change text color for all future output (until reset) /// ```dart /// print('hello'); // prints in terminal default color /// print(ConsoleColor.red.enableForeground); /// print('hello'); // prints in red color /// ``` String get enableForeground => '$ansiEscapeLiteral[38;2;$r;$g;${b}m'; /// Change text color for all future output (until reset) /// ```dart /// print('hello'); // prints in terminal default color /// print(ConsoleColor.red.enableBackground); /// print('hello'); // prints with red background color /// ``` String get enableBackground => '$ansiEscapeLiteral[48;2;$r;$g;${b}m'; /// Reset text and background color to terminal defaults static String get reset => '$ansiEscapeLiteral[0m'; /// Sets text color for the input String applyForeground(String text) { return '$ansiEscapeLiteral[38;2;$r;$g;${b}m$text$reset'; } /// Sets background color and then resets the color change String applyBackground(String text) { return '$ansiEscapeLiteral[48;2;$r;$g;${b}m$text$ansiEscapeLiteral[0m'; } }Estos métodos usan códigos de escape ANSI para aplicar colores de primer plano y fondo al texto. Los métodos
applyForegroundyapplyBackgrounddevuelven una cadena con los códigos de escape ANSI aplicados.
Tarea 2: Crear una extensión de String
#A continuación, crea una extensión sobre la clase String para
añadir métodos de utilidad para aplicar colores de consola y dar formato al texto.
-
Añade el siguiente código al archivo
command_runner/lib/src/console.dart:command_runner/lib/src/console.dartdart// Add this code to the bottom of the file extension TextRenderUtils on String { String get errorText => ConsoleColor.red.applyForeground(this); String get instructionText => ConsoleColor.yellow.applyForeground(this); String get titleText => ConsoleColor.lightBlue.applyForeground(this); List<String> splitLinesByLength(int length) { final List<String> words = split(' '); final List<String> output = <String>[]; final StringBuffer strBuffer = StringBuffer(); for (int i = 0; i < words.length; i++) { final String word = words[i]; if (strBuffer.length + word.length <= length) { strBuffer.write(word.trim()); if (strBuffer.length + 1 <= length) { strBuffer.write(' '); } } // If the next word surpasses length, start the next line if (i + 1 < words.length && words[i + 1].length + strBuffer.length + 1 > length) { output.add(strBuffer.toString().trim()); strBuffer.clear(); } } // Add left overs output.add(strBuffer.toString().trim()); return output; } }Este código define una extensión llamada
TextRenderUtilssobre la claseString. Añade tres métodos getter para aplicar colores de consola:errorText,instructionTextytitleText. También añade un método para dividir una cadena en líneas de una longitud específica llamadosplitLinesByLength.
Tarea 3: Actualizar el paquete command_runner
#Actualiza el paquete command_runner para exportar console.dart.
-
Open
command_runner/lib/command_runner.dartand add the following line:command_runner/lib/command_runner.dartdartlibrary; export 'src/arguments.dart'; export 'src/command_runner_base.dart'; export 'src/exceptions.dart'; export 'src/help_command.dart'; export 'src/console.dart'; // Add this line // TODO: Export any libraries intended for clients of this package.
Tarea 4: Implementar el comando echo colorido
#Por último, implementa un comando de ejemplo para probar la impresión. En Dart, es una buena práctica implementar ejemplos de uso de un paquete para los desarrolladores que vayan a utilizar tu paquete. Este ejemplo crea un comando que añade color a la salida de la consola.
Abre el archivo
example/command_runner_example.dart.-
Reemplaza el contenido del archivo con el siguiente código:
command_runner/example/command_runner_example.dartdartimport 'dart:async'; import 'package:command_runner/command_runner.dart'; class PrettyEcho extends Command { PrettyEcho() { addFlag( 'blue-only', abbr: 'b', help: 'When true, the echoed text will all be blue.', ); } @override String get name => 'echo'; @override bool get requiresArgument => true; @override String get description => 'Print input, but colorful.'; @override String? get help => 'echos a String provided as an argument with ANSI coloring,'; @override String? get valueHelp => 'STRING'; @override FutureOr<String> run(ArgResults arg) { if (arg.commandArg == null) { throw ArgumentException( 'This argument requires one positional argument', name, ); } List<String> prettyWords = []; var words = arg.commandArg!.split(' '); for (var i = 0; i < words.length; i++) { var word = words[i]; switch (i % 3) { case 0: prettyWords.add(word.titleText); case 1: prettyWords.add(word.instructionText); case 2: prettyWords.add(word.errorText); } } return prettyWords.join(' '); } } void main(List<String> arguments) { final runner = CommandRunner()..addCommand(PrettyEcho()); runner.run(arguments); }Este código define un comando
PrettyEchoque extiende la claseCommand. Toma una cadena de texto como argumento y aplica diferentes colores a cada palabra basándose en su posición en la cadena. El métodorunusa los métodos gettertitleText,instructionTextyerrorTextde la extensiónTextRenderUtilspara aplicar los colores. -
Navega a
/dartpedia/command_runnery ejecuta el siguiente comando:bashdart run example/command_runner_example.dart echo "hello world goodbye"Deberías ver el siguiente texto impreso en la consola, con la primera palabra en azul claro, la segunda en amarillo y la tercera en rojo.
bashhello world goodbye
Revisión
#Qué lograste
Aquí tienes un resumen de lo que construiste y aprendiste en esta lección.Usaste enums mejorados con campos y métodos
Creaste ConsoleColor como un enum mejorado con campos r, g, b
y métodos como applyForeground(). Los enums mejorados pueden tener constructores, propiedades y métodos, combinando los beneficios de los enums y de las clases normales.
Extendiste tipos existentes con extensiones
Creaste una extensión TextRenderUtils sobre la clase String para añadir getters como
errorText y titleText a todas las cadenas. Las extensiones te permiten añadir funcionalidad a cualquier tipo sin necesidad de modificarlo o crear subclases, lo cual es especialmente útil en casos como las cadenas de texto (strings), que no se pueden subclasificar.
Agregaste salida de consola colorida
Para mejorar la legibilidad y la experiencia de usuario de tu CLI, usaste códigos de escape ANSI para dar estilo con colores a la salida de la terminal. En particular, usaste
ConsoleColor y actualizaste tu CLI para mostrar los errores en rojo, los títulos en azul y las instrucciones en amarillo.
Cuestionario
#Pon a prueba tu comprensión
1 / 3Un enum que es generado automáticamente por el compilador de Dart.
No exactamente.
Los enums los defines tú, no se generan automáticamente. "Mejorado" se refiere a lo que puedes hacer dentro de la definición del enum.
Un enum que puede tener métodos y propiedades.
¡Correcto!
Los enums mejorados te permiten agregar campos, constructores y métodos a los tipos enum, haciéndolos mucho más potentes que las enumeraciones simples.
Un enum que solo puede tener valores de tipo string.
No exactamente.
Los enums mejorados no están limitados a ningún tipo en particular. La parte "mejorada" se refiere a capacidades adicionales más allá de la enumeración básica.
Un enum que solo se puede usar en aplicaciones Flutter.
No exactamente.
Los enums mejorados son una característica principal de Dart disponible en todas las aplicaciones Dart, no solo en Flutter.
Una forma de definir nuevos operadores en Dart.
No exactamente.
Aunque las extensiones pueden definir operadores, ese no es su propósito principal o único. Son más generales que solo operadores.
Una forma de agregar nuevos métodos a clases existentes.
¡Correcto!
Las extensiones te permiten agregar nueva funcionalidad a tipos existentes sin modificarlos ni crear subclases.
Una forma de crear nuevas variables en Dart.
No exactamente.
Las variables se crean con declaraciones como
varofinal. Las extensiones sirven para un propósito diferente.Una forma de crear nuevas clases a partir de clases existentes.
No exactamente.
Crear nuevas clases a partir de clases existentes se hace mediante herencia (
extends) o composición. Las extensiones no crean nuevos tipos.
capitalizeWords() method to String, but you can't modify the String class. What's the best approach?Crear una función global
capitalizeWords(String s)en su lugar.No exactamente.
Las funciones globales funcionan, pero puede que no se lean de forma natural y a menudo son difíciles de descubrir.
capitalizeWords(text)es menos intuitivo quetext.capitalizeWords(). Dart ofrece una forma de lograr esto último.Crear una clase
MyStringque envuelva aStringy añada el método.No exactamente.
Las clases wrapper funcionan pero requieren convertir entre tipos en todas partes. Hay un enfoque más limpio que no requiere wrapping.
Crear una extensión sobre
Stringque añada el método.¡Correcto!
Las extensiones te permiten añadir métodos a tipos existentes. Luego puedes llamar a
'hello world'.capitalizeWords()como sicapitalizeWordsestuviera integrado enString.Crear una subclase de
Stringcon el nuevo método.No exactamente.
Stringes un tipo fundamental de Dart que no se puede subclasificar. Necesitas un enfoque diferente para añadirle métodos.
Siguiente lección
#En la siguiente lección, aprenderás a
mejorar aún más el paquete command_runner
puliendo el HelpCommand, completando la clase CommandRunner,
añadiendo el argumento onOutput y proporcionando un ejemplo completo.
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 13-04-2026. Ver fuente oreportar un problema.