Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parser.adding(...).default(...) does not work #23

Closed
ice-phoenix opened this issue Aug 8, 2017 · 4 comments
Closed

parser.adding(...).default(...) does not work #23

ice-phoenix opened this issue Aug 8, 2017 · 4 comments

Comments

@ice-phoenix
Copy link

As parser.adding(...) creates default delegate by itself (ArgParser.kt:137), nested default delegates are confused as to whose default value should be used, and it does not work.

@jjoller
Copy link

jjoller commented Dec 19, 2017

In case you need a workaround:

val listOfStrings: List<String> by ListWithDefault(
            parser.adding(names = *arrayOf("-l", "--list"), help = "Help text...")
            ,listOf("defaultValue"))
class ListWithDefault<T>(val delegate: ArgParser.Delegate<MutableList<T>>, val default: List<T>) {
    operator fun provideDelegate(thisRef: kotlin.Any?, prop: kotlin.reflect.KProperty<*>): ListWithDefault<T> {
        delegate.provideDelegate(thisRef, prop)
        return this
    }
    operator fun getValue(config: Configuration, prop: KProperty<*>): List<T> = if (delegate.value.isEmpty()) {
        default
    } else {
        delegate.value
    }
}

@xenomachina
Copy link
Owner

This is the intended behavior: default only has an effect in cases where the underlying delegate would have complained about a missing value. That can't happen with delegates created by adding (or flagging).

That said, I am considering revamping how defaults work in a future release, and if there are issues with the current semantics, this would be the right time to adjust them. I'm curious to know the use-case here, so while I am closing this issue for now, please feel free to add comments if you'd like to influence that future redesign.

@jjoller
Copy link

jjoller commented Dec 21, 2017

The use-case is to "add" one or multiple arguments and to provide a default if no argument is passed. Why is this not a valid use-case? Does the library provide a way to achieve this?

@xenomachina
Copy link
Owner

Sorry if I wasn't clear. I was not asking for the general behavior you want -- I already knew that. I'm asking for specific examples of where this would be useful.

As for whether the library provides a way to achieve this: yes, but not as conveniently.

The methods on ArgParser like adding, flagging, etc. are convenience wrappers around ArgParser.option. They don't use any private APIs (except for PosixNaming, which is a bug -- see also #42 ). You can create you own wrappers around option. eg:

fun <E, T : MutableCollection<E>> ArgParser.addingWithDefault(
        name: String,
        default: () -> T,
        help: String,
        argName: String,
        initialValue: T,
        transform: String.() -> E
): ArgParser.Delegate<T> {
    return option<T>(
            name,
            help = help,
            argNames = listOf(argName),
            isRepeating = true) {
        val result = value.orElse { initialValue }
        result.add(transform(arguments.first()))
        result
    }.default(default())
}

Now you can do something like:

    val differentWhenEmpty by parser.addingWithDefault(
            "-X",
            { mutableListOf("def0", "def1", "def2") },
            help = "list of things",
            argName = "X",
            initialValue = mutableListOf("init0", "init1", "init2")) { this }

Not passing -X will give you the list [def0, def1, def2], but passing -X one -X two will give you ["init0", "init1", "init2", "one", "two"].

So you can do it, but it obviously isn't as convenient as using the existing adding method.

An even simpler approach is to use adding, and then simply to treat the empty list as a case where you should use you default list instead.

As I mentioned, if there are common cases where people actually need this behavior, then I'm happy to consider changing the behavior in a future release. So far I haven't seen any concrete examples, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants