This commit is contained in:
LepilkinaElena
2019-09-18 09:44:39 +03:00
committed by GitHub
parent 09b21d687e
commit 52c5fd1fef
7 changed files with 35 additions and 29 deletions
@@ -180,14 +180,14 @@ open class ArgParser(val programName: String, var useDefaultHelpShortName: Boole
// Previous argument has default value.
it.descriptor.defaultValue?.let {
if (currentArgument.descriptor.defaultValue == null && currentArgument.descriptor.required) {
printWarning("Default value of argument ${previousArgument.descriptor.fullName} will be unused, " +
printError("Default value of argument ${previousArgument.descriptor.fullName} will be unused, " +
"because next argument ${currentArgument.descriptor.fullName} is always required and has no default value.")
}
}
// Previous argument is optional.
if (!it.descriptor.required) {
if (currentArgument.descriptor.defaultValue == null && currentArgument.descriptor.required) {
printWarning("Argument ${previousArgument.descriptor.fullName} will be always required, " +
printError("Argument ${previousArgument.descriptor.fullName} will be always required, " +
"because next argument ${currentArgument.descriptor.fullName} is always required.")
}
}
@@ -313,7 +313,7 @@ open class ArgParser(val programName: String, var useDefaultHelpShortName: Boole
// Add default list with arguments if there can be extra free arguments.
if (skipExtraArguments) {
argument(ArgType.String, "").number()
argument(ArgType.String, "").vararg()
}
// Map declared options and arguments to maps.
@@ -87,7 +87,7 @@ class SingleNullableArgument<T : Any> internal constructor(descriptor: ArgDescri
class MultipleArgument<T : Any> internal constructor(descriptor: ArgDescriptor<T, List<T>>, owner: CLIEntityWrapper):
Argument<List<T>>(owner) {
init {
if (descriptor.number != null && descriptor.number == 1) {
if (descriptor.number != null && descriptor.number < 2) {
failAssertion("Argument with multiple values can't be initialized with descriptor for single one.")
}
delegate = ArgumentMultipleValues(descriptor)
@@ -97,11 +97,11 @@ class MultipleArgument<T : Any> internal constructor(descriptor: ArgDescriptor<T
/**
* Allow argument have several values.
*
* @param number number of arguments are expected. In case of null value any number of arguments can be set.
* @param value number of arguments are expected.
*/
fun <T : Any, TResult> AbstractSingleArgument<T, TResult>.number(value: Int? = null): MultipleArgument<T> {
if (value != null && value == 1) {
error("number() modifier with value 1 is unavailable. It's already set to 1.")
fun <T : Any, TResult> AbstractSingleArgument<T, TResult>.multiple(value: Int): MultipleArgument<T> {
if (value < 2) {
error("multiple() modifier with value less than 2 is unavailable. It's already set to 1.")
}
val newArgument = with((delegate as ParsingValue<T, T>).descriptor as ArgDescriptor) {
MultipleArgument(ArgDescriptor(type, fullName, value, description, listOfNotNull(defaultValue),
@@ -111,6 +111,18 @@ fun <T : Any, TResult> AbstractSingleArgument<T, TResult>.number(value: Int? = n
return newArgument
}
/**
* Allow argument have several values.
*/
fun <T : Any, TResult> AbstractSingleArgument<T, TResult>.vararg(): MultipleArgument<T> {
val newArgument = with((delegate as ParsingValue<T, T>).descriptor as ArgDescriptor) {
MultipleArgument(ArgDescriptor(type, fullName, null, description, listOfNotNull(defaultValue),
required, deprecatedWarning), owner)
}
owner.entity = newArgument
return newArgument
}
/**
* Set default value for argument.
*
@@ -130,6 +142,9 @@ fun <T: Any, TResult> AbstractSingleArgument<T, TResult>.default(value: T): Sing
* @param value default value.
*/
fun <T: Any> MultipleArgument<T>.default(value: Collection<T>): MultipleArgument<T> {
if (value.isEmpty()) {
error("Default value for argument can't be empty collection.")
}
val newArgument = with((delegate as ParsingValue<T, List<T>>).descriptor as ArgDescriptor) {
MultipleArgument(ArgDescriptor(type, fullName, number, description, value.toList(),
required, deprecatedWarning), owner)
@@ -141,7 +156,7 @@ fun <T: Any> MultipleArgument<T>.default(value: Collection<T>): MultipleArgument
/**
* Allow argument be unprovided in command line.
*/
fun <T: Any, TResult> AbstractSingleArgument<T, TResult>.optional(): SingleNullableArgument<T> {
fun <T: Any> SingleArgument<T>.optional(): SingleNullableArgument<T> {
val newArgument = with((delegate as ParsingValue<T, T>).descriptor as ArgDescriptor) {
SingleNullableArgument(ArgDescriptor(type, fullName, number, description, defaultValue,
false, deprecatedWarning), owner)
@@ -127,7 +127,7 @@ internal class ArgDescriptor<T : Any, TResult>(
init {
// Check arguments number correctness.
number?.let {
if (it < 0)
if (it < 1)
error("Number of arguments for argument description $fullName should be greater than zero.")
}
}
@@ -116,9 +116,6 @@ fun <T : Any> MultipleOption<T, DelimitedOption>.multiple(): MultipleOption<T, R
*/
fun <T: Any, TResult> AbstractSingleOption<T, TResult>.default(value: T): SingleOption<T> {
val newOption = with((delegate as ParsingValue<T, T>).descriptor as OptionDescriptor) {
if (required) {
printWarning("required() is unneeded, because option with default value is defined.")
}
SingleOption(OptionDescriptor(optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
description, value, required, multiple, delimiter, deprecatedWarning), owner)
}
@@ -134,8 +131,8 @@ fun <T: Any, TResult> AbstractSingleOption<T, TResult>.default(value: T): Single
fun <T: Any, OptionType: MultipleOptionType>
MultipleOption<T, OptionType>.default(value: Collection<T>): MultipleOption<T, OptionType> {
val newOption = with((delegate as ParsingValue<T, List<T>>).descriptor as OptionDescriptor) {
if (required) {
printWarning("required() is unneeded, because option with default value is defined.")
if (value.isEmpty()) {
error("Default value for option can't be empty collection.")
}
MultipleOption<T, OptionType>(OptionDescriptor(optionFullFormPrefix, optionShortFromPrefix, type, fullName,
shortName, description, value.toList(),
@@ -148,11 +145,8 @@ fun <T: Any, OptionType: MultipleOptionType>
/**
* Require option to be always provided in command line.
*/
fun <T: Any, TResult> AbstractSingleOption<T, TResult>.required(): SingleOption<T> {
fun <T: Any> SingleNullableOption<T>.required(): SingleOption<T> {
val newOption = with((delegate as ParsingValue<T, T>).descriptor as OptionDescriptor) {
defaultValue?.let {
printWarning("required() is unneeded, because option with default value is defined.")
}
SingleOption(OptionDescriptor(optionFullFormPrefix, optionShortFromPrefix, type, fullName,
shortName, description, defaultValue,
true, multiple, delimiter, deprecatedWarning), owner)
@@ -167,9 +161,6 @@ fun <T: Any, TResult> AbstractSingleOption<T, TResult>.required(): SingleOption<
fun <T: Any, OptionType: MultipleOptionType>
MultipleOption<T, OptionType>.required(): MultipleOption<T, OptionType> {
val newOption = with((delegate as ParsingValue<T, List<T>>).descriptor as OptionDescriptor) {
if (required) {
printWarning("required() is unneeded, because option with default value is defined.")
}
MultipleOption<T, OptionType>(OptionDescriptor(optionFullFormPrefix, optionShortFromPrefix, type, fullName, shortName,
description, defaultValue?.toList() ?: listOf(),
true, multiple, delimiter, deprecatedWarning), owner)
@@ -26,7 +26,7 @@ class ArgumentsTests {
fun testArgumetsWithAnyNumberOfValues() {
val argParser = ArgParser("testParser")
val output by argParser.argument(ArgType.String, "output", "Output file")
val inputs by argParser.argument(ArgType.String, description = "Input files").number()
val inputs by argParser.argument(ArgType.String, description = "Input files").vararg()
argParser.parse(arrayOf("out.txt", "input1.txt", "input2.txt", "input3.txt",
"input4.txt"))
assertEquals("out.txt", output)
@@ -36,7 +36,7 @@ class ArgumentsTests {
@Test
fun testArgumetsWithSeveralValues() {
val argParser = ArgParser("testParser")
val addendums by argParser.argument(ArgType.Int, "addendums", description = "Addendums").number(2)
val addendums by argParser.argument(ArgType.Int, "addendums", description = "Addendums").multiple(2)
val output by argParser.argument(ArgType.String, "output", "Output file")
val debugMode by argParser.option(ArgType.Boolean, "debug", "d", "Debug mode")
argParser.parse(arrayOf("2", "-d", "3", "out.txt"))
@@ -50,7 +50,7 @@ class ArgumentsTests {
@Test
fun testSkippingExtraArguments() {
val argParser = ArgParser("testParser", skipExtraArguments = true)
val addendums by argParser.argument(ArgType.Int, "addendums", description = "Addendums").number(2)
val addendums by argParser.argument(ArgType.Int, "addendums", description = "Addendums").multiple(2)
val output by argParser.argument(ArgType.String, "output", "Output file")
val debugMode by argParser.option(ArgType.Boolean, "debug", "d", "Debug mode")
argParser.parse(arrayOf("2", "-d", "3", "out.txt", "something", "else", "in", "string"))
@@ -13,7 +13,7 @@ class ErrorTests {
@Test
fun testExtraArguments() {
val argParser = ArgParser("testParser")
val addendums by argParser.argument(ArgType.Int, "addendums", description = "Addendums").number(2)
val addendums by argParser.argument(ArgType.Int, "addendums", description = "Addendums").multiple(2)
val output by argParser.argument(ArgType.String, "output", "Output file")
val debugMode by argParser.option(ArgType.Boolean, "debug", "d", "Debug mode")
val exception = assertFailsWith<IllegalStateException> { argParser.parse(
@@ -18,7 +18,7 @@ class SubcommandsTests {
val output by argParser.option(ArgType.String, "output", "o", "Output file")
class Summary: Subcommand("summary") {
val invert by option(ArgType.Boolean, "invert", "i", "Invert results")
val addendums by argument(ArgType.Int, "addendums", description = "Addendums").number()
val addendums by argument(ArgType.Int, "addendums", description = "Addendums").vararg()
var result: Int = 0
override fun execute() {
@@ -36,7 +36,7 @@ class SubcommandsTests {
@Test
fun testCommonOptions() {
abstract class CommonOptions(name: String): Subcommand(name) {
val numbers by argument(ArgType.Int, "numbers", description = "Numbers").number()
val numbers by argument(ArgType.Int, "numbers", description = "Numbers").vararg()
}
class Summary: CommonOptions("summary") {
val invert by option(ArgType.Boolean, "invert", "i", "Invert results")
@@ -74,7 +74,7 @@ class SubcommandsTests {
val argParser = ArgParser("testParser")
class Summary: Subcommand("summary") {
val addendums by argument(ArgType.Int, "addendums", description = "Addendums").number()
val addendums by argument(ArgType.Int, "addendums", description = "Addendums").vararg()
var result: Int = 0
override fun execute() {