improve exceptions
This commit is contained in:
@@ -7,11 +7,9 @@ import com.infendro.cli.command.context.ContextParser
|
||||
import com.infendro.cli.command.help.DefaultHelpRenderer
|
||||
import com.infendro.cli.command.help.HelpRenderer
|
||||
import com.infendro.cli.command.option.Option
|
||||
import com.infendro.cli.exception.build.*
|
||||
import com.infendro.cli.error.build.*
|
||||
import com.infendro.cli.parser.*
|
||||
import com.infendro.cli.util.Regex
|
||||
import com.infendro.cli.util.Regex.ARGUMENT
|
||||
import com.infendro.cli.util.Regex.OPTION
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
sealed class Command private constructor(
|
||||
@@ -205,15 +203,11 @@ sealed class Command private constructor(
|
||||
argument.required && last.optional -> throw InvalidArgumentOrder()
|
||||
}
|
||||
}
|
||||
if (!argument.name.matches(ARGUMENT)) throw InvalidArgument(argument.name)
|
||||
}
|
||||
|
||||
private fun validateOption(option: Option<*>) {
|
||||
for (name in option.names) {
|
||||
when {
|
||||
!name.matches(OPTION) -> throw InvalidOption(name)
|
||||
options.any { name in it.names } -> throw DuplicateOption(name)
|
||||
}
|
||||
if (options.any { name in it.names }) throw DuplicateOption(name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +216,7 @@ sealed class Command private constructor(
|
||||
}
|
||||
|
||||
private fun validateRenderer() {
|
||||
if (_renderer != null) throw Exception() //TODO
|
||||
if (_renderer != null) throw DuplicateRenderer()
|
||||
}
|
||||
|
||||
private fun validate() {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.infendro.cli.command.argument
|
||||
|
||||
import com.infendro.cli.exception.build.InvalidRange
|
||||
import com.infendro.cli.error.build.InvalidArgument
|
||||
import com.infendro.cli.error.build.InvalidRange
|
||||
import com.infendro.cli.parser.Parser
|
||||
import com.infendro.cli.util.Regex.ARGUMENT
|
||||
|
||||
sealed class Argument<T : Any>(
|
||||
val parser: Parser<T>,
|
||||
@@ -10,7 +12,10 @@ sealed class Argument<T : Any>(
|
||||
val max: Int?,
|
||||
) {
|
||||
init {
|
||||
if (min !in 0..count || max == 0) throw InvalidRange()
|
||||
when {
|
||||
!name.matches(ARGUMENT) -> throw InvalidArgument(name)
|
||||
min !in 0..count || max == 0 -> throw InvalidRange()
|
||||
}
|
||||
}
|
||||
|
||||
val required: Boolean
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.infendro.cli.command.context
|
||||
|
||||
import com.infendro.cli.command.Command
|
||||
import com.infendro.cli.exception.run.*
|
||||
import com.infendro.cli.error.run.*
|
||||
import com.infendro.cli.parser.Parser
|
||||
|
||||
internal class ContextParser(
|
||||
@@ -19,13 +19,13 @@ internal class ContextParser(
|
||||
|
||||
data class Failure(
|
||||
val command: Command,
|
||||
val error: RuntimeError,
|
||||
val error: RunError,
|
||||
) : Result()
|
||||
}
|
||||
|
||||
private fun success(context: Context) = Result.Success(context)
|
||||
private fun help(command: Command) = Result.Help(command)
|
||||
private fun failure(command: Command, exception: RuntimeError) = Result.Failure(command, exception)
|
||||
private fun failure(command: Command, exception: RunError) = Result.Failure(command, exception)
|
||||
|
||||
private var index = 0
|
||||
private val current: String
|
||||
|
||||
@@ -75,7 +75,11 @@ object DefaultHelpRenderer : HelpRenderer {
|
||||
private fun StringBuilder.commands(commands: List<Command>) {
|
||||
appendLine("Commands:")
|
||||
for (command in commands) {
|
||||
appendLine(" * ${command.name}")
|
||||
val name = when {
|
||||
command is Command.Fallback<*> -> "<${command.name}>"
|
||||
else -> command.name
|
||||
}
|
||||
appendLine(" * $name")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.infendro.cli.command.option
|
||||
|
||||
import com.infendro.cli.exception.build.InvalidRange
|
||||
import com.infendro.cli.exception.build.MissingOptionName
|
||||
import com.infendro.cli.error.build.InvalidOption
|
||||
import com.infendro.cli.error.build.InvalidRange
|
||||
import com.infendro.cli.error.build.MissingOptionName
|
||||
import com.infendro.cli.parser.Parser
|
||||
import com.infendro.cli.util.Regex.OPTION
|
||||
|
||||
sealed class Option<T : Any>(
|
||||
val parser: Parser<T>,
|
||||
@@ -33,6 +35,7 @@ sealed class Option<T : Any>(
|
||||
init {
|
||||
when {
|
||||
names.isEmpty() -> throw MissingOptionName()
|
||||
names.any { !it.matches(OPTION) } -> throw InvalidOption(name)
|
||||
min !in 0..count || max == 0 -> throw InvalidRange()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ object OptionFactory {
|
||||
fun long(vararg names: String) = option(LongParser, *names)
|
||||
fun float(vararg names: String) = option(FloatParser, *names)
|
||||
fun double(vararg names: String) = option(DoubleParser, *names)
|
||||
fun boolean(vararg names: String) = option(BooleanParser, true, *names)
|
||||
fun boolean(vararg names: String) = option(BooleanParser, fallback = true, *names)
|
||||
|
||||
inline fun <reified T : Enum<T>> enum(vararg names: String) = option(enumParser<T>(), *names)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
abstract class BuildException : Error()
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class DuplicateCommand(
|
||||
val command: String,
|
||||
) : BuildException() {
|
||||
override val message: String
|
||||
get() = """duplicate command "$command""""
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class DuplicateExecute : BuildException() {
|
||||
override val message: String
|
||||
get() = """duplicate execute block"""
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class DuplicateOption(
|
||||
val name: String,
|
||||
) : BuildException() {
|
||||
override val message: String
|
||||
get() = """duplicate option "$name""""
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class DuplicateRenderer : BuildException() {
|
||||
override val message: String
|
||||
get() = """duplicate renderer"""
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class InvalidArgument(
|
||||
val name: String,
|
||||
) : BuildException() {
|
||||
override val message: String
|
||||
get() = """invalid argument name "$name""""
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class InvalidArgumentOrder : BuildException() {
|
||||
override val message: String
|
||||
get() = """invalid argument order"""
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class InvalidCommand(
|
||||
val name: String,
|
||||
) : BuildException() {
|
||||
override val message: String
|
||||
get() = """invalid command name "$name""""
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class InvalidCommandOrder : BuildException() {
|
||||
override val message: String
|
||||
get() = """invalid command order"""
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class InvalidFallback : BuildException() {
|
||||
override val message: String
|
||||
get() = """invalid fallback"""
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class InvalidOption(
|
||||
val name: String,
|
||||
) : BuildException() {
|
||||
override val message: String
|
||||
get() = """invalid option name "$name""""
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class InvalidRange : BuildException() {
|
||||
override val message: String
|
||||
get() = """invalid range"""
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.infendro.cli.error.build
|
||||
|
||||
class MissingOptionName : BuildException() {
|
||||
override val message: String
|
||||
get() = """missing option name"""
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.infendro.cli.exception.run
|
||||
package com.infendro.cli.error.run
|
||||
|
||||
import com.infendro.cli.command.argument.Argument
|
||||
|
||||
class InvalidArgumentCount(
|
||||
val argument: Argument<*>,
|
||||
val count: Int,
|
||||
) : RuntimeError() {
|
||||
) : RunError() {
|
||||
override val message: String
|
||||
get() {
|
||||
val expected = when {
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.infendro.cli.exception.run
|
||||
package com.infendro.cli.error.run
|
||||
|
||||
import com.infendro.cli.command.option.Option
|
||||
|
||||
class InvalidOptionCount(
|
||||
val option: Option<*>,
|
||||
val count: Int,
|
||||
) : RuntimeError() {
|
||||
) : RunError() {
|
||||
override val message: String
|
||||
get() {
|
||||
val expected = when {
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.infendro.cli.exception.run
|
||||
package com.infendro.cli.error.run
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class InvalidValue(
|
||||
val value: String,
|
||||
val type: KClass<*>,
|
||||
) : RuntimeError() {
|
||||
) : RunError() {
|
||||
override val message: String
|
||||
get() = """"$value" cannot be converted to ${type.simpleName ?: "Unknown"}"""
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.infendro.cli.exception.run
|
||||
package com.infendro.cli.error.run
|
||||
|
||||
class MalformedOption(
|
||||
val option: String,
|
||||
) : RuntimeError() {
|
||||
) : RunError() {
|
||||
override val message: String
|
||||
get() = """malformed option "$option""""
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.infendro.cli.exception.run
|
||||
package com.infendro.cli.error.run
|
||||
|
||||
import com.infendro.cli.command.option.Option
|
||||
|
||||
class MissingOptionValue(
|
||||
val option: Option<*>,
|
||||
) : RuntimeError() {
|
||||
) : RunError() {
|
||||
override val message: String
|
||||
get() = """no value provided for option "${option.name}""""
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.infendro.cli.error.run
|
||||
|
||||
abstract class RunError {
|
||||
abstract val message: String
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.infendro.cli.error.run
|
||||
|
||||
class UnexpectedArgument : RunError() {
|
||||
override val message: String
|
||||
get() = """unexpected argument"""
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.infendro.cli.exception.run
|
||||
package com.infendro.cli.error.run
|
||||
|
||||
class UnknownCommand(
|
||||
val command: String,
|
||||
) : RuntimeError() {
|
||||
) : RunError() {
|
||||
override val message: String
|
||||
get() = """unknown command "$command""""
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.infendro.cli.exception.run
|
||||
package com.infendro.cli.error.run
|
||||
|
||||
class UnknownOption(
|
||||
val option: String,
|
||||
) : RuntimeError() {
|
||||
) : RunError() {
|
||||
override val message: String
|
||||
get() = """unknown option "$option""""
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
abstract class CliException : Exception()
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class DuplicateCommand(
|
||||
val command: String,
|
||||
) : CliException()
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class DuplicateExecute : CliException()
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class DuplicateOption(
|
||||
val name: String,
|
||||
) : CliException()
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class InvalidArgument(
|
||||
val name: String,
|
||||
) : CliException()
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class InvalidArgumentOrder : CliException()
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class InvalidCommand(
|
||||
val name: String,
|
||||
) : CliException()
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class InvalidCommandOrder : CliException()
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class InvalidFallback : CliException()
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class InvalidOption(
|
||||
val name: String,
|
||||
) : CliException()
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class InvalidRange : CliException()
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.infendro.cli.exception.build
|
||||
|
||||
class MissingOptionName : CliException()
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.infendro.cli.exception.run
|
||||
|
||||
abstract class RuntimeError {
|
||||
abstract val message: String
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.infendro.cli.exception.run
|
||||
|
||||
class UnexpectedArgument : RuntimeError() {
|
||||
override val message: String
|
||||
get() = """unexpected argument"""
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.infendro.cli.parser
|
||||
|
||||
import com.infendro.cli.exception.run.InvalidValue
|
||||
import com.infendro.cli.exception.run.RuntimeError
|
||||
import com.infendro.cli.error.run.InvalidValue
|
||||
import com.infendro.cli.error.run.RunError
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
abstract class Parser<T : Any>(
|
||||
@@ -13,7 +13,7 @@ abstract class Parser<T : Any>(
|
||||
) : Result<T>()
|
||||
|
||||
data class Failure<T : Any>(
|
||||
val error: RuntimeError,
|
||||
val error: RunError,
|
||||
) : Result<T>()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user