Skip to content

Commit 5f3bc57

Browse files
authored
Add option().groupSwitch() (#95)
1 parent e291285 commit 5f3bc57

File tree

6 files changed

+101
-12
lines changed

6 files changed

+101
-12
lines changed

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# Changelog
22

33
## [Unreleased]
4-
### Changed
5-
- Shell completion code is now printed by throwing a `PrintCompletionMessage` (a subclass of `PrintMessage`) rather than calling `echo` directly.
6-
74
### Added
5+
- `option().groupSwitch()`, which works like `groupChoice()`, but uses a `switch()` option rather than a `choice()` option.
86
- `UsageError` now has a `statusCode` parameter (which defaults to 1). If you're using `ClicktCommand.main`, the value of `statusCode` will be passed to `exitProcess`.
97

8+
### Changed
9+
- Shell completion code is now printed by throwing a `PrintCompletionMessage` (a subclass of `PrintMessage`) rather than calling `echo` directly.
10+
1011
## [2.2.0] - 2019-09-25
1112
### Added
1213
- Added [`enum()` conversion](https://ajalt.github.io/clikt/api/clikt/com.github.ajalt.clikt.parameters.types/enum/) for options and arguments. ([#84](https://github.com/ajalt/clikt/issues/84))

clikt/src/main/kotlin/com/github/ajalt/clikt/parameters/groups/ChoiceGroup.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import com.github.ajalt.clikt.core.Context
77
import com.github.ajalt.clikt.core.MissingParameter
88
import com.github.ajalt.clikt.parameters.internal.NullableLateinit
99
import com.github.ajalt.clikt.parameters.options.Option
10+
import com.github.ajalt.clikt.parameters.options.OptionDelegate
1011
import com.github.ajalt.clikt.parameters.options.RawOption
12+
import com.github.ajalt.clikt.parameters.options.switch
1113
import com.github.ajalt.clikt.parsers.OptionParser
1214
import kotlin.properties.ReadOnlyProperty
1315
import kotlin.reflect.KProperty
1416

1517
class ChoiceGroup<GroupT : OptionGroup, OutT>(
16-
internal val option: RawOption,
18+
internal val option: OptionDelegate<String?>,
1719
internal val groups: Map<String, GroupT>,
1820
internal val transform: (GroupT?) -> OutT
1921
) : ParameterGroupDelegate<OutT> {
@@ -103,3 +105,28 @@ fun <T : OptionGroup> ChoiceGroup<T, T?>.required(): ChoiceGroup<T, T> {
103105
return ChoiceGroup(option, groups) { it ?: throw MissingParameter(option) }
104106
}
105107

108+
/**
109+
* Convert the option into a set of flags that each map to an option group.
110+
*
111+
* ### Example:
112+
*
113+
* ```kotlin
114+
* option().switch(mapOf("--foo" to FooOptionGroup(), "--bar" to BarOptionGroup()))
115+
* ```
116+
*/
117+
fun <T : OptionGroup> RawOption.groupSwitch(choices: Map<String, T>): ChoiceGroup<T, T?> {
118+
return ChoiceGroup(switch(choices.mapValues { it.key }), choices) { it }
119+
}
120+
121+
/**
122+
* Convert the option into a set of flags that each map to an option group.
123+
*
124+
* ### Example:
125+
*
126+
* ```kotlin
127+
* option().switch("--foo" to FooOptionGroup(), "--bar" to BarOptionGroup())
128+
* ```
129+
*/
130+
fun <T : OptionGroup> RawOption.groupSwitch(vararg choices: Pair<String, T>): ChoiceGroup<T, T?> {
131+
return groupSwitch(choices.toMap())
132+
}

clikt/src/main/kotlin/com/github/ajalt/clikt/parameters/options/FlagOption.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,15 @@ fun RawOption.counted(): FlagOption<Int> {
118118
validator = {})
119119
}
120120

121-
/** Turn an option into a set of flags that each map to a value. */
121+
/**
122+
* Turn an option into a set of flags that each map to a value.
123+
*
124+
* ### Example:
125+
*
126+
* ```kotlin
127+
* option().switch(mapOf("--foo" to Foo(), "--bar" to Bar()))
128+
* ```
129+
*/
122130
fun <T : Any> RawOption.switch(choices: Map<String, T>): FlagOption<T?> {
123131
require(choices.isNotEmpty()) { "Must specify at least one choice" }
124132
return FlagOption(choices.keys, emptySet(), help, hidden, helpTags, null,
@@ -129,7 +137,15 @@ fun <T : Any> RawOption.switch(choices: Map<String, T>): FlagOption<T?> {
129137
validator = {})
130138
}
131139

132-
/** Turn an option into a set of flags that each map to a value. */
140+
/**
141+
* Turn an option into a set of flags that each map to a value.
142+
*
143+
* ### Example:
144+
*
145+
* ```kotlin
146+
* option().switch("--foo" to Foo(), "--bar" to Bar())
147+
* ```
148+
*/
133149
fun <T : Any> RawOption.switch(vararg choices: Pair<String, T>): FlagOption<T?> = switch(mapOf(*choices))
134150

135151
/** Set a default value for a option. */

clikt/src/test/kotlin/com/github/ajalt/clikt/parameters/groups/OptionGroupsTest.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,49 @@ class OptionGroupsTest {
287287
.message shouldBe "Invalid value for \"--g\": invalid choice: 3. (choose from 1, 2)"
288288
}
289289

290+
@Test
291+
fun `switch group`() {
292+
class Group1 : OptionGroup() {
293+
val g11 by option().int().required()
294+
val g12 by option().int()
295+
}
296+
297+
class Group2 : OptionGroup() {
298+
val g21 by option().int().required()
299+
val g22 by option().int()
300+
}
301+
302+
class C : TestCommand() {
303+
val g by option().groupSwitch("--a" to Group1(), "--b" to Group2())
304+
}
305+
forall(
306+
row("", 0, null, null),
307+
row("--g11=1 --g21=1", 0, null, null),
308+
row("--a --g11=2", 1, 2, null),
309+
row("--a --g11=2 --g12=3", 1, 2, 3),
310+
row("--a --g11=2 --g12=3", 1, 2, 3),
311+
row("--b --g21=2 --g22=3", 2, 2, 3),
312+
row("--b --g11=2 --g12=3 --g21=2 --g22=3", 2, 2, 3)
313+
) { argv, eg, eg1, eg2 ->
314+
with(C()) {
315+
parse(argv)
316+
when (eg) {
317+
0 -> {
318+
g shouldBe null
319+
}
320+
1 -> {
321+
(g as Group1).g11 shouldBe eg1
322+
(g as Group1).g12 shouldBe eg2
323+
}
324+
2 -> {
325+
(g as Group2).g21 shouldBe eg1
326+
(g as Group2).g22 shouldBe eg2
327+
}
328+
}
329+
}
330+
}
331+
}
332+
290333
@Test
291334
fun `plain option group validation`() = forall(
292335
row("", null, true),

docs/options.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -483,15 +483,16 @@ Error: Missing option "--name".
483483
Like [other option groups][grouping-options-in-help], you can specify a `name` and
484484
`help` text for the group if you want to set the group apart in the help output.
485485

486-
## Choice Options With Groups
486+
## Choice and Switch Options With Groups
487487

488488
If you have different groups of options that only make sense when another option has a certain value,
489-
you can use [`groupChoice`][groupChoice].
489+
you can use [`groupChoice`][groupChoice] and [`groupSwitch`][groupSwitch].
490490

491-
These options are similar to [`choice` options][choice-options], but instead of mapping a value to
491+
`groupChoice` options are similar to [`choice` options][choice-options], but instead of mapping a value to
492492
a single new type, they map a value to a [co-occurring `OptionGroup`][co-occurring-option-groups].
493493
Options for groups other than the selected one are ignored, and only the selected group's `required`
494-
constraints are enforced.
494+
constraints are enforced. In the same way, `groupSwitch` options are similar to [`switch`
495+
options][choice-options].
495496

496497
```kotlin tab="Example"
497498
sealed class LoadConfig(name: String): OptionGroup(name)
@@ -896,7 +897,8 @@ val opt: Pair<Int, Int> by option("-o", "--opt")
896897
[cooccurring]: api/clikt/com.github.ajalt.clikt.parameters.groups/cooccurring.md
897898
[required]: api/clikt/com.github.ajalt.clikt.parameters.options/required.md
898899
[groupChoice]: api/clikt/com.github.ajalt.clikt.parameters.groups/group-choice.md
899-
[choice-options]: #choice-options
900+
[groupChoice]: api/clikt/com.github.ajalt.clikt.parameters.groups/group-switch.md
901+
[switch-options]: #feature-switch-flags
900902
[co-occurring-option-groups]: #co-occurring-option-groups
901903
[prompt]: api/clikt/com.github.ajalt.clikt.parameters.options/prompt.md
902904
[versionOption]: api/clikt/com.github.ajalt.clikt.parameters.options/version-option.md

mkdocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ nav:
6464
- 'Choice Options': options/#choice-options
6565
- 'Mutually Exclusive Option Groups': options/#mutually-exclusive-option-groups
6666
- 'Co-Occurring Option Groups': options/#co-occurring-option-groups
67-
- 'Choice Options With Groups': options/#choice-options-with-groups
67+
- 'Choice and Switch Options With Groups': options/#choice-and-switch-options-with-groups
6868
- 'Prompting For Input': options/#prompting-for-input
6969
- 'Password Prompts': options/#password-prompts
7070
- 'Eager Options': options/#eager-options

0 commit comments

Comments
 (0)