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()

Reply via email to