Accept one of a fixed set of values
When an option may only be one of a handful of values, use a Kotlin enum and let Argot do the matching. You get validation, a listing in the error message, and a real type on the other side.
Use .enum<E>()
import org.draftcode.argot.Arguments
enum class Level { DEBUG, INFO, WARN, ERROR }
class LogArgs : Arguments(programName = "log", description = "Read the log.") {
val level: Level by option("--level", "-l", help = "Minimum level")
.enum<Level>()
.default(Level.INFO)
}The property is a Level, not a string you have to re-check:
fun atLeast(args: LogArgs): List<Level> = Level.entries.filter { it >= args.level }Matching is already case-insensitive
You do not have to lowercase anything. All of these parse to Level.WARN:
$ log --level warn
$ log --level WARN
$ log --level WarnThe comparison is against each constant's name, so the value the user types and the constant you declared do not have to agree on case — only on spelling.
Bad values name the type
$ log --level loud
error: invalid value 'loud' for --level (expected Level)Listing the valid values
The message names the type but does not enumerate the constants. If your enum's name is not self-explanatory, put the options in the option's help text — that is what users see on --help:
val level: Level by option("--level", "-l", help = "One of debug, info, warn, error")
.enum<Level>()
.default(Level.INFO)Defaults are typed
.default(Level.INFO) takes a Level, not the string "INFO", so a typo is a compile error rather than a runtime surprise. The help screen renders it with the constant's name:
$ log --help
Options:
--level, -l <Level> Minimum level (default: INFO)In the annotation style
The parameter's type selects the converter, so an enum parameter just works. Here default is a string because annotation arguments must be compile-time constants. The generated code runs it through the same converter when the parser is built, so a default that is not a valid constant fails on the first parse rather than silently becoming something else:
@Command(name = "log", description = "Read the log.")
data class LogArgs(
@Option(names = ["--level", "-l"], help = "Minimum level", default = "INFO")
val level: Level,
)See also
EnumConverterandenumConverter.- Write a converter for your own type when a fixed set is not enough.