experimental types for @Unparsed (closes #308)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/05abc726 Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/05abc726 Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/05abc726 Branch: refs/heads/master Commit: 05abc726fecf23b95c16d6a002c4c83b33ebeddc Parents: 17fbbb8 Author: paulk <pa...@asert.com.au> Authored: Mon Apr 11 20:31:08 2016 +1000 Committer: paulk <pa...@asert.com.au> Committed: Wed Apr 13 20:39:47 2016 +1000 ---------------------------------------------------------------------- src/main/groovy/util/CliBuilder.groovy | 41 +++++++++++++++---------- src/test/groovy/util/CliBuilderTest.groovy | 25 +++++++++++++++ 2 files changed, 50 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/05abc726/src/main/groovy/util/CliBuilder.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/CliBuilder.groovy b/src/main/groovy/util/CliBuilder.groovy index a5027b4..bc7d44a 100644 --- a/src/main/groovy/util/CliBuilder.groovy +++ b/src/main/groovy/util/CliBuilder.groovy @@ -303,12 +303,6 @@ class CliBuilder { Options options = new Options() Map<String, TypedOption> savedTypeOptions = new HashMap<String, TypedOption>() - /* - Object defaultValue = map.get("defaultValue"); - defaultValues.put(makeDefaultValueKey(option), defaultValue); - Class type = (Class) map.get("type"); - if (type != null) option.setType(type); - */ public <T> TypedOption<T> option(Map args, Class<T> type, String description) { def name = args.opt ?: '_' @@ -528,21 +522,31 @@ class CliBuilder { } def remaining = cli.arguments() optionClass.methods.findAll{ it.getAnnotation(Unparsed) }.each { Method m -> - processSetRemaining(m, remaining, t, namesAreSetters) + processSetRemaining(m, remaining, t, cli, namesAreSetters) } optionClass.declaredFields.findAll{ it.getAnnotation(Unparsed) }.each { Field f -> String setterName = "set" + MetaClassHelper.capitalize(f.getName()); Method m = optionClass.getMethod(setterName, f.getType()) - processSetRemaining(m, remaining, t, namesAreSetters) + processSetRemaining(m, remaining, t, cli, namesAreSetters) } } - private void processSetRemaining(Method m, remaining, Object t, boolean namesAreSetters) { + private void processSetRemaining(Method m, remaining, Object t, cli, boolean namesAreSetters) { + def resultType = namesAreSetters ? m.parameterTypes[0] : m.returnType + def isTyped = resultType?.isArray() + def result + def type = null + if (isTyped) { + type = resultType.componentType + result = remaining.collect{ cli.getValue(type, it, null) } + } else { + result = remaining.toList() + } if (namesAreSetters) { - m.invoke(t, remaining.toList()) + m.invoke(t, isTyped ? [result.toArray(Array.newInstance(type, result.size()))] as Object[] : result) } else { Map names = calculateNames("", "", m, namesAreSetters) - t.put(names.long, { -> remaining.toList() }) + t.put(names.long, { -> result }) } } @@ -729,14 +733,19 @@ class OptionAccessor { } private <T> T getTypedValue(Class<T> type, String optionName, String optionValue) { + if (savedTypeOptions[optionName]?.cliOption?.numberOfArgs == 0) { + return (T) commandLine.hasOption(optionName) + } + def convert = savedTypeOptions[optionName]?.convert + return getValue(type, optionValue, convert) + } + + private <T> T getValue(Class<T> type, String optionValue, Closure convert) { if (!type) { return (T) optionValue } - if (Closure.isAssignableFrom(type) && savedTypeOptions[optionName]?.convert) { - return (T) savedTypeOptions[optionName].convert(optionValue) - } - if (savedTypeOptions[optionName]?.cliOption?.numberOfArgs == 0) { - return (T) commandLine.hasOption(optionName) + if (Closure.isAssignableFrom(type) && convert) { + return (T) convert(optionValue) } if (type?.simpleName?.toLowerCase() == 'boolean') { return (T) Boolean.parseBoolean(optionValue) http://git-wip-us.apache.org/repos/asf/groovy/blob/05abc726/src/test/groovy/util/CliBuilderTest.groovy ---------------------------------------------------------------------- diff --git a/src/test/groovy/util/CliBuilderTest.groovy b/src/test/groovy/util/CliBuilderTest.groovy index aa3d680..175228b 100644 --- a/src/test/groovy/util/CliBuilderTest.groovy +++ b/src/test/groovy/util/CliBuilderTest.groovy @@ -620,6 +620,31 @@ usage: groovy ' cv.txt, DOWN, [and, some, more])' } + interface RetTypeI { + @Unparsed Integer[] nums() + } + + // this feature is incubating + void testTypedUnparsedFromSpec() { + def argz = '12 34 56'.split() + def cli = new CliBuilder() + def options = cli.parseFromSpec(RetTypeI, argz) + assert options.nums() == [12, 34, 56] + } + + class RetTypeC { + @Unparsed Integer[] nums + } + + // this feature is incubating + void testTypedUnparsedFromInstance() { + def argz = '12 34 56'.split() + def cli = new CliBuilder() + def options = new RetTypeC() + cli.parseFromInstance(options, argz) + assert options.nums == [12, 34, 56] + } + interface FlagEdgeCasesI { @Option boolean abc() @Option(numberOfArgumentsString='1') boolean efg()