Skip to content

Commit

Permalink
Fix Issue #47
Browse files Browse the repository at this point in the history
If an option looks at the value of another option it can see the current
value. If no value has been set a MissingValueException is thrown.
  • Loading branch information
xenomachina committed Mar 26, 2018
1 parent c9ede31 commit 413c8fa
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 37 deletions.
78 changes: 42 additions & 36 deletions src/main/kotlin/com/xenomachina/argparser/ArgParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -443,19 +443,20 @@ class ArgParser(
* @throws SystemExitException if parsing or validation failed.
*/
fun force() {
if (!finished) {
parseOptions
if (!inValidation) {
inValidation = true
try {
for (delegate in delegates) delegate.checkHasValue()
for (delegate in delegates) delegate.validate()
} finally {
inValidation = false
if (!inParse) {
if (!finished) {
parseOptions
if (!inValidation) {
inValidation = true
try {
for (delegate in delegates) delegate.checkHasValue()
for (delegate in delegates) delegate.validate()
} finally {
inValidation = false
}
}
}
}
finished = true
}

/**
Expand All @@ -470,44 +471,49 @@ class ArgParser(
return provided
}

private var parseStarted = false
private var inParse = false

internal fun checkNotParsed() {
if (parseStarted) throw IllegalStateException("arguments have already been parsed")
if (inParse || finished) throw IllegalStateException("arguments have already been parsed")
}

private val parseOptions by lazy {
val positionalArguments = mutableListOf<String>()
parseStarted = true
var i = 0
optionLoop@ while (i < args.size) {
val arg = args[i]
i += when {
arg == "--" -> {
i++
break@optionLoop
}
arg.startsWith("--") ->
parseLongOpt(i, args)
arg.startsWith("-") ->
parseShortOpts(i, args)
else -> {
positionalArguments.add(arg)
when (mode) {
Mode.GNU -> 1
Mode.POSIX -> {
i++
break@optionLoop
inParse = true
try {
var i = 0
optionLoop@ while (i < args.size) {
val arg = args[i]
i += when {
arg == "--" -> {
i++
break@optionLoop
}
arg.startsWith("--") ->
parseLongOpt(i, args)
arg.startsWith("-") ->
parseShortOpts(i, args)
else -> {
positionalArguments.add(arg)
when (mode) {
Mode.GNU -> 1
Mode.POSIX -> {
i++
break@optionLoop
}
}
}
}
}
}

// Collect remaining arguments as positional-only arguments
positionalArguments.addAll(args.slice(i..args.size - 1))
// Collect remaining arguments as positional-only arguments
positionalArguments.addAll(args.slice(i..args.size - 1))

parsePositionalArguments(positionalArguments)
parsePositionalArguments(positionalArguments)
finished = true
} finally {
inParse = false
}
}

private fun parsePositionalArguments(args: List<String>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal abstract class ParsingDelegate<T>(
override val value: T
get() {
parser.force()
// checkHasValue should have ensured that this is non-null
checkHasValue()
return holder!!.value
}

Expand Down
37 changes: 37 additions & 0 deletions src/test/kotlin/com/xenomachina/argparser/ArgParserTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1571,3 +1571,40 @@ class Issue18Test_DefaultThenValidator : Test({
val x = Args(parserOf()).x
x shouldEqual 0
})

class Issue47Test : Test({
class Args(parser: ArgParser) {
val caseInsensitive by parser.flagging("-c", "--case_insensitive", help = TEST_HELP)

val includedExtensions by parser.adding("-e", "--include_ext", help = TEST_HELP) {
extensionCheckCaseInsensitive()
}

private fun String.extensionCheckCaseInsensitive() =
if (caseInsensitive) this.toLowerCase() else this
}

val includeExtensions = Args(parserOf("-e", "Foo", "-c", "-e", "Bar")).includedExtensions
includeExtensions shouldEqual listOf("Foo", "bar")
})

class DependentArgs(parser: ArgParser) {
val suffix by parser.storing(TEST_HELP)

val x by parser.adding(TEST_HELP) {
"$this:$suffix"
}
}

class DependentArgsTest_orderMatters : Test({
val result = DependentArgs(parserOf("--suffix", "bar", "-x", "foo", "-x", "dry", "--suffix", "fish", "-x", "cat")).x
result shouldEqual listOf("foo:bar", "dry:bar", "cat:fish")
})

class DependentArgsTest_unsetThrowsMissingValueException : Test({
shouldThrow<MissingValueException> {
DependentArgs(parserOf("-x", "foo", "-x", "dry", "--suffix", "fish", "-x", "cat")).x
}.run {
message shouldEqual "missing SUFFIX"
}
})

0 comments on commit 413c8fa

Please sign in to comment.