additional tests and doco tweaks

Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/dac0bd84
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/dac0bd84
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/dac0bd84

Branch: refs/heads/master
Commit: dac0bd84bf042e6ff489053918d5bd8203482a0e
Parents: 952ac01
Author: paulk <pa...@asert.com.au>
Authored: Sun Apr 10 14:09:52 2016 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Wed Apr 13 20:38:54 2016 +1000

----------------------------------------------------------------------
 src/main/groovy/cli/Option.java                 |  4 +-
 src/main/groovy/cli/Unparsed.java               |  2 +-
 src/main/groovy/util/CliBuilder.groovy          |  5 +-
 .../doc/core-domain-specific-languages.adoc     |  8 +-
 src/test/groovy/util/CliBuilderTest.groovy      | 95 ++++++++++++++++++++
 5 files changed, 107 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/dac0bd84/src/main/groovy/cli/Option.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/cli/Option.java b/src/main/groovy/cli/Option.java
index 453a51a..9b48861 100644
--- a/src/main/groovy/cli/Option.java
+++ b/src/main/groovy/cli/Option.java
@@ -26,7 +26,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Indicates that a method or field can be used to set a CLI option.
+ * Indicates that a method or property can be used to set a CLI option.
  */
 @java.lang.annotation.Documented
 @Retention(RetentionPolicy.RUNTIME)
@@ -40,7 +40,7 @@ public @interface Option {
     String description() default "";
 
     /**
-     * The short name of this option. Defaults to the name of member being 
annotated.
+     * The short name of this option. Defaults to the name of member being 
annotated if the longName is empty.
      *
      * @return the short name of this option
      */

http://git-wip-us.apache.org/repos/asf/groovy/blob/dac0bd84/src/main/groovy/cli/Unparsed.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/cli/Unparsed.java 
b/src/main/groovy/cli/Unparsed.java
index d615cf1..a741413 100644
--- a/src/main/groovy/cli/Unparsed.java
+++ b/src/main/groovy/cli/Unparsed.java
@@ -24,7 +24,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Indicates that a method will contain the remaining arguments.
+ * Indicates that a method or property will contain the remaining arguments.
  */
 @java.lang.annotation.Documented
 @Retention(RetentionPolicy.RUNTIME)

http://git-wip-us.apache.org/repos/asf/groovy/blob/dac0bd84/src/main/groovy/util/CliBuilder.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/util/CliBuilder.groovy 
b/src/main/groovy/util/CliBuilder.groovy
index 30537b0..91d2938 100644
--- a/src/main/groovy/util/CliBuilder.groovy
+++ b/src/main/groovy/util/CliBuilder.groovy
@@ -501,8 +501,9 @@ class CliBuilder {
         if (namesAreSetters) {
             def isBoolArg = m.parameterTypes.size() > 0 && 
m.parameterTypes[0].simpleName.toLowerCase() == 'boolean'
             boolean isFlag = (isBoolArg && !hasArg) || noArg
-            if (cli.hasOption(name) || isFlag) {
-                m.invoke(t, [isFlag ? cli.hasOption(name) : optionValue(cli, 
name)] as Object[])
+            if (cli.hasOption(name) || isFlag || cli.defaultValue(name)) {
+                m.invoke(t, [isFlag ? cli.hasOption(name) :
+                                     cli.hasOption(name) ? optionValue(cli, 
name) : cli.defaultValue(name)] as Object[])
             }
         } else {
             def isBoolRetType = m.returnType.simpleName.toLowerCase() == 
'boolean'

http://git-wip-us.apache.org/repos/asf/groovy/blob/dac0bd84/src/spec/doc/core-domain-specific-languages.adoc
----------------------------------------------------------------------
diff --git a/src/spec/doc/core-domain-specific-languages.adoc 
b/src/spec/doc/core-domain-specific-languages.adoc
index 6c5245a..8210f5b 100644
--- a/src/spec/doc/core-domain-specific-languages.adoc
+++ b/src/spec/doc/core-domain-specific-languages.adoc
@@ -1233,7 +1233,8 @@ and populates it. You simply call the interface methods 
to interrogate the optio
 
 Alternatively, perhaps you already have a domain class containing the option 
information.
 You can simply annotate properties or setters from that class to enable 
`CliBuilder` to appropriately
-populate your domain object.
+populate your domain object. Each annotation both describes that option's 
properties through the annotation
+attributes and indicates the setter the `CliBuilder` will use to populate that 
option in your domain object.
 
 Here is how such a specification can be defined:
 
@@ -1430,7 +1431,7 @@ e.g. `String x = someVariable ?: 'some default'`. But 
sometimes you wish to make
 options specification to minimise the interrogators work in later stages. 
`CliBuilder` supports the `defaultValue`
 property to cater for this scenario.
 
-Here is how you could use it using the deynamic api style:
+Here is how you could use it using the dynamic api style:
 
 [source,groovy]
 ----
@@ -1452,6 +1453,9 @@ Which would be used like this:
 
include::{projectdir}/src/spec/test/builder/CliBuilderTest.groovy[tags=withDefaultValueInterface,indent=0]
 ----
 
+You can also use the `defaultValue` annotation attribute when using 
annotations with an instance,
+though it's probably just as easy to provide an initial value for the property 
(or backing field).
+
 ===== Use with `TypeChecked`
 
 The dynamic api style of using `CliBuilder` is inherently dynamic but you have 
a few options

http://git-wip-us.apache.org/repos/asf/groovy/blob/dac0bd84/src/test/groovy/util/CliBuilderTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/util/CliBuilderTest.groovy 
b/src/test/groovy/util/CliBuilderTest.groovy
index 4ec52d0..826e2cd 100644
--- a/src/test/groovy/util/CliBuilderTest.groovy
+++ b/src/test/groovy/util/CliBuilderTest.groovy
@@ -21,6 +21,7 @@ package groovy.util
 import groovy.cli.Option
 import groovy.cli.Unparsed
 import groovy.transform.ToString
+import groovy.transform.TypeChecked
 import org.apache.commons.cli.BasicParser
 import org.apache.commons.cli.DefaultParser
 import org.apache.commons.cli.GnuParser
@@ -519,6 +520,100 @@ usage: groovy
             this.remaining = remaining
         }
     }
+    class DefaultValueC {
+        @Option(shortName='f', defaultValue='one') String from
+        @Option(shortName='t', defaultValue='35') int to
+        @Option(shortName='b') int by = 1
+    }
+
+    void testDefaultValueClass() {
+        def cli = new CliBuilder()
+        def options = new DefaultValueC()
+        cli.parseFromInstance(options, '-f two'.split())
+        assert options.from == 'two'
+        assert options.to == 35
+        assert options.by == 1
+
+        options = new DefaultValueC()
+        cli.parseFromInstance(options, '-t 45 --by 2'.split())
+        assert options.from == 'one'
+        assert options.to == 45
+        assert options.by == 2
+    }
+
+    class ValSepC {
+        @Option(numberOfArguments=2) String[] a
+        @Option(numberOfArgumentsString='2', valueSeparator=',') String[] b
+        @Option(numberOfArgumentsString='+', valueSeparator=',') String[] c
+        @Unparsed remaining
+    }
+
+    void testValSepClass() {
+        def cli = new CliBuilder()
+
+        def options = new ValSepC()
+        cli.parseFromInstance(options, '-a 1 2 3 4'.split())
+        assert options.a == ['1', '2']
+        assert options.remaining == ['3', '4']
+
+        options = new ValSepC()
+        cli.parseFromInstance(options, '-a1 -a2 3'.split())
+        assert options.a == ['1', '2']
+        assert options.remaining == ['3']
+
+        options = new ValSepC()
+        cli.parseFromInstance(options, ['-b1,2'] as String[])
+        assert options.b == ['1', '2']
+
+        options = new ValSepC()
+        cli.parseFromInstance(options, ['-c', '1'] as String[])
+        assert options.c == ['1']
+
+        options = new ValSepC()
+        cli.parseFromInstance(options, ['-c1'] as String[])
+        assert options.c == ['1']
+
+        options = new ValSepC()
+        cli.parseFromInstance(options, ['-c1,2,3'] as String[])
+        assert options.c == ['1', '2', '3']
+    }
+
+    class WithConvertC {
+        @Option(convert={ it.toLowerCase() }) String a
+        @Option(convert={ it.toUpperCase() }) String b
+        @Option(convert={ Date.parse("yyyy-MM-dd", it) }) Date d
+        @Unparsed List remaining
+    }
+
+    void testConvertClass() {
+        Date newYears = Date.parse("yyyy-MM-dd", "2016-01-01")
+        def argz = '''-a John -b Mary -d 2016-01-01 and some more'''.split()
+        def cli = new CliBuilder()
+        def options = new WithConvertC()
+        cli.parseFromInstance(options, argz)
+        assert options.a == 'john'
+        assert options.b == 'MARY'
+        assert options.d == newYears
+        assert options.remaining == ['and', 'some', 'more']
+    }
+
+    class TypeCheckedC {
+        @Option String name
+        @Option int age
+        @Unparsed List remaining
+    }
+
+    @TypeChecked
+    void testTypeCheckedClass() {
+        def argz = "--name John --age 21 and some more".split()
+        def cli = new CliBuilder()
+        def options = new TypeCheckedC()
+        cli.parseFromInstance(options, argz)
+        String n = options.name
+        int a = options.age
+        assert n == 'John' && a == 21
+        assert options.remaining == ['and', 'some', 'more']
+    }
 
     void testParseFromInstance() {
         def p2 = new PersonC()

Reply via email to