Skip to content

Commit

Permalink
Add associate overloads (#533)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajalt authored Jul 20, 2024
1 parent 015ee1d commit 5c56161
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Added `Context.exitProcess` which you can use to prevent the process from exiting during tests.
- Added core module that supports watchOS, tvOS, and wasmWasi targets and has no dependencies.
- Added more options to `CliktCommand.test` to control the terminal interactivity. ([#517](https://github.com/ajalt/clikt/pull/517))
- Added `associate{}`, `associateBy{}`, and `associateWith{}' transforms for options that allow you to convert the keys and values of the map. ([#529](https://github.com/ajalt/clikt/pull/529))

### Changed
- In a subcommand with `argument().multiple()`, the behavior is now the same regardless of the value of `allowMultipleSubcommands`: if a token matches a subcommand name, it's now treated as a subcommand rather than a positional argument.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,28 @@ class OptionTest {
C().parse(argv)
}

@Test
@JsName("associate_conversion_options")
fun `associate conversion options`() = forAll(
row("", emptyMap(), emptyMap(), emptyMap()),
row(
"-Xa=1 -Yb=2 -Zc=3", mapOf("A" to 1), mapOf("B" to "2"), mapOf("c" to 3),
)
) { argv, ex, ey, ez ->
class C : TestCommand() {
val x by option("-X").associate { (k, v) -> k.uppercase() to v.toInt() }
val y by option("-Y").associateBy { it.uppercase() }
val z by option("-Z").associateWith { it.toInt() }
override fun run_() {
x shouldBe ex
y shouldBe ey
z shouldBe ez
}
}
C().parse(argv)
}


@Test
@JsName("customized_splitPair")
fun `customized splitPair`() = forAll(
Expand Down
6 changes: 6 additions & 0 deletions clikt/api/clikt.api
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,13 @@ public final class com/github/ajalt/clikt/parameters/options/OptionWithValues$De

public final class com/github/ajalt/clikt/parameters/options/OptionWithValuesKt {
public static final fun associate (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Ljava/lang/String;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
public static final fun associate (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
public static synthetic fun associate$default (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Ljava/lang/String;ILjava/lang/Object;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
public static synthetic fun associate$default (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
public static final fun associateBy (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
public static synthetic fun associateBy$default (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
public static final fun associateWith (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
public static synthetic fun associateWith$default (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
public static final fun convert (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Ljava/lang/String;Lcom/github/ajalt/clikt/completion/CompletionCandidates;Lkotlin/jvm/functions/Function2;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
public static final fun convert (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Lkotlin/jvm/functions/Function1;Lcom/github/ajalt/clikt/completion/CompletionCandidates;Lkotlin/jvm/functions/Function2;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
public static synthetic fun convert$default (Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;Ljava/lang/String;Lcom/github/ajalt/clikt/completion/CompletionCandidates;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/github/ajalt/clikt/parameters/options/OptionWithValues;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ fun <EachT, ValueT> NullableOption<EachT, ValueT>.multiple(
* val opt2: Set<Int> by option().int().split(",").default(emptyList()).unique()
* ```
*/
fun <T, EachT, ValueT> OptionWithValues<List<T>, EachT, ValueT>.unique(): OptionWithValues<Set<T>, EachT, ValueT> {
fun <T, EachT, ValueT> OptionWithValues<List<T>, EachT, ValueT>.unique()
: OptionWithValues<Set<T>, EachT, ValueT> {
return copy(transformValue, transformEach, { transformAll(it).toSet() }, defaultValidator())
}

Expand All @@ -153,7 +154,8 @@ fun <T, EachT, ValueT> OptionWithValues<List<T>, EachT, ValueT>.unique(): Option
*
* If the same key appears more than once, the last one will be added to the map.
*/
fun <A, B, EachT, ValueT> OptionWithValues<List<Pair<A, B>>, EachT, ValueT>.toMap(): OptionWithValues<Map<A, B>, EachT, ValueT> {
fun <A, B, EachT, ValueT> OptionWithValues<List<Pair<A, B>>, EachT, ValueT>.toMap()
: OptionWithValues<Map<A, B>, EachT, ValueT> {
return copy(transformValue, transformEach, { transformAll(it).toMap() }, defaultValidator())
}

Expand All @@ -165,3 +167,38 @@ fun <A, B, EachT, ValueT> OptionWithValues<List<Pair<A, B>>, EachT, ValueT>.toMa
fun RawOption.associate(delimiter: String = "="): OptionWithValues<Map<String, String>, Pair<String, String>, Pair<String, String>> {
return splitPair(delimiter).multiple().toMap()
}

/**
* Change this option to take multiple values, each split on a [delimiter] and converted with the
* [transform] function and converted to a map.
*
* This is shorthand for [splitPair], [convert], [multiple], and [toMap].
*/
inline fun <K, V> RawOption.associate(
delimiter: String = "=",
crossinline transform: (Pair<String, String>) -> Pair<K, V>,
): OptionWithValues<Map<K, V>, Pair<K, V>, Pair<K, V>> {
return splitPair(delimiter).convert { transform(it) }.multiple().toMap()
}

/**
* Change this option to take multiple values, each split on a [delimiter], its first value
* converted with the [keySelector], and converted to a map.
*/
inline fun <K> RawOption.associateBy(
delimiter: String = "=",
crossinline keySelector: (String) -> K,
): OptionWithValues<Map<K, String>, Pair<K, String>, Pair<K, String>> {
return associate(delimiter) { keySelector(it.first) to it.second }
}

/**
* Change this option to take multiple values, each split on a [delimiter], its second value
* converted with the [valueSelector], and converted to a map.
*/
inline fun <V> RawOption.associateWith(
delimiter: String = "=",
crossinline valueSelector: (String) -> V,
): OptionWithValues<Map<String, V>, Pair<String, V>, Pair<String, V>> {
return associate(delimiter) { it.first to valueSelector(it.second) }
}

0 comments on commit 5c56161

Please sign in to comment.