Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pgreze/kyper
Functional Kotlin friendly way to create command line applications.
https://github.com/pgreze/kyper
kotlin kotlin-cli kotlin-functional-programming
Last synced: about 2 months ago
JSON representation
Functional Kotlin friendly way to create command line applications.
- Host: GitHub
- URL: https://github.com/pgreze/kyper
- Owner: pgreze
- License: apache-2.0
- Created: 2023-01-01T10:45:43.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-08-17T08:49:14.000Z (over 1 year ago)
- Last Synced: 2024-08-01T19:56:35.233Z (5 months ago)
- Topics: kotlin, kotlin-cli, kotlin-functional-programming
- Language: Kotlin
- Homepage: https://pgreze.github.io/kyper/
- Size: 106 KB
- Stars: 17
- Watchers: 2
- Forks: 1
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-list - pgreze/kyper - Functional Kotlin friendly way to create command line applications. (Kotlin)
README
# kyper [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![](https://github.com/pgreze/kyper/actions/workflows/main.yml/badge.svg)](https://github.com/pgreze/kyper/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/pgreze/kyper/branch/main/graph/badge.svg?token=T5R37803P4)](https://codecov.io/gh/pgreze/kyper)
Functional Kotlin friendly way to create command line applications.
It comes from the basic need to have a function like:
```kotlin
fun main(
content: String,
target: File,
mode: Mode = Mode.APPEND,
) {
TODO()
}enum class Mode { APPEND, OVERWRITE }
```with all the behaviors we expect when using it in our code:
- supports more data types than just String, i.e. File/Path/Enum/etc
- mode being an optional parameterand turns it into a command line application powered by Kotlin script.
This library is solving this need 🪄
> Kyper? Is it a name?
This library is hugely inspired by the wonderful [typer](https://typer.tiangolo.com/)
from the Python ecosystem.Also naming is hard 😇
> But we already have [clikt](https://ajalt.github.io/clikt/)? (or any alternative)
Correct, but I try to keep my Kotlin scripts as small as possible,
and having to deal with classes is not what I would describe as simple.Also chained property delegates are great,
but I always need to read the documentation to figure out all the options.> So let's migrate everything to this wonderful library?
For simple usecases like Kotlin scripts, feel free.
For more complex applications, where readability is important,
I would stick with [clikt](https://ajalt.github.io/clikt/)
or any alternative not relying on ~magic~ reflection
and/or implicit behaviors like this library is doing.## Installation [![central](https://maven-badges.herokuapp.com/maven-central/com.github.pgreze/kyper/badge.svg?style={style})](https://search.maven.org/artifact/com.github.pgreze/kyper) ![](https://img.shields.io/badge/Java-11-blue) [![](https://img.shields.io/badge/Kotlin-1.7.22-blue)](https://kotlinlang.org/)
```kotlin
repositories {
mavenCentral()
}dependencies {
// Check the 🔝 maven central badge 🔝 for the latest $kyperVersion
implementation("com.github.pgreze:kyper:$kyperVersion")
}
```Or in your kotlin script:
```kotlin
@file:DependsOn("com.github.pgreze:kyper:$kyperVersion")
```## Usage with function(s)
### Start with a single function
We can start by defining a simple function handling our logic:
```kotlin
#!/usr/bin/env kotlinc -scriptimport com.github.pgreze.kyper.Command
import com.github.pgreze.kyper.Parameter
import com.github.pgreze.kyper.kyper@Commmand("function help message")
fun main(
@Parameter("the name to greet")
name: String
) {
println("hello $name")
}kyper().invoke(args)
```And run it with the name parameter:
```bash
$ ./script.main.kts there
hello there
```Notice we also defined help messages for both the command and its parameter:
```bash
$ # Use `--` to indicate that the following arguments are for the script, not kotlinc itself
$ ./script.main.kts -- --help
Usage: main NAMEfunction help message
Options:
-h, --help Show this message and exitArguments:
NAME the name to greet
```### Only @Command annotated methods are exported
Our script can declare more methods, without exposing them as command:
```kotlin
#!/usr/bin/env kotlinc -scriptimport com.github.pgreze.kyper.Command
import com.github.pgreze.kyper.kyper@Command
fun main(name: String) {
greet(name)
}fun greet(name: String) {
println("Hello $name")
}kyper().invoke(args)
```Usage is the same:
```bash
$ ./script.main.kts there
hello there
```But having several `@Command` functions will turn our application into a multi-command mode:
```kotlin
#!/usr/bin/env kotlinc -scriptimport com.github.pgreze.kyper.Command
import com.github.pgreze.kyper.kyper@Command("Say hello in English")
fun hello(name: String) {
println("hello $name")
}@Command("Say hello in French")
fun bonjour(name: String) {
println("bonjour $name")
}kyper(help = "Say hello to your user").invoke(args)
```We can now notice several commands are available by calling --help:
```bash
$ ./kyper/hellos.main.kts -- --help
Usage: [OPTIONS] COMMAND [ARGS]...Say hello to your user
Options:
-h, --help Show this message and exitCommands:
BONJOUR Say hello in French
HELLO Say hello in English
```Each command can be requested for `--help`:
```
$ ./kyper/hellos.main.kts -- --help bonjour
Usage: bonjour NAMESay hello in French
Options:
-h, --help Show this message and exitArguments:
NAME
```### Handle more than strings as arguments
The following types are supported:
```kotlin
fun main(
string: String = "arg",
int: Int = 1,
float: Float = 1.2f,
double: Double = 3.14,
long: Long = Long.MAX_VALUE,
boolean: Boolean = true,
bigInteger: BigInteger = BigInteger.valueOf(12),
bigDecimal: BigDecimal = BigDecimal.valueOf(12.3),
file: File = File("file"),
path: Path = Path.of("path"),
choice: Choice = Choice.NO,
vararg strings: String, // For vararg, only String/File are supported.
) {
TODO()
}enum class Choice { YES, NO }
```### Default values (unstable)
As shown in the last code block,
default values are supported
as long as they're at the end of the method.🚨️ WIP: the current implementation is quite simple; it is
just based on parameter positioning,
and does not allow any `--flag` logic.## Usage with lambda(s) (experimental)
If the Kotlin DSL syntax is something you're looking for in your Kotlin script,
this library also provides a similar syntax based on lambdas:```kotlin
#!/usr/bin/env kotlinc -script@file:Suppress("OPT_IN_USAGE")
import com.github.pgreze.kyper.kyper
kyper(help = "Run multiple commands from Kotlin script with ease") {
register(name = "time", help = "Display current timestamp") { ->
println(System.currentTimeMillis())
}register(name = "greet") { name ->
println("Hello $name")
}
}.invoke(args)
```But this comes with restrictions:
- no default argument(s),
- up to 4 arguments,
- only String type is supported.This may be dropped in the future if we cannot reach
the same support level as the functions-based usage.