Mar 21, 2013

GExcelAPI 0.3 Released!

GExcelAPI is a Groovy-Excel Wrapper introduced at the entry http://nobeans-en.blogspot.jp/2011/11/gexcelapi-for-groovyist-using-ms-excel.html.

Changelog of 0.3 is very tiny.
  • Supported Java 7
  • Upgraded POI to 3.9
You can get from the following repositories:
Sample of usage:
  1. @GrabResolver(name="my", root="https://repository-kobo.forge.cloudbees.com/release")  
  2. @Grab("org.jggug.kobo:gexcelapi:0.3")  
  3. import org.jggug.kobo.gexcelapi.GExcel  
  4.   
  5. def book = GExcel.open(args[0])  
  6.   
  7. assert book.sheets[0].A1.value == "Sheet1-A1"  
The unit tests make the API look good:

Dec 7, 2012

Grails Improx Plugin 0.1, codenamed GrailsServ, released!


I'm very pleased to announce the release of improx plugin, which provides the way of using interactive mode from other process via TCP.

If you install this plugin to your application, you can invoke any Grails commands on an interactive mode, which started up in advance on a console, from other processes via a  TCP. This means that you can quickly run a test which is opened in you favorite editor or IDE. If you've appropriately set them up, you'd have only to push a key in order to run it.
(from Introduction of Improx Plugin User Guide)


In short, you can quickly run a single test which you're editing now, by one action. If you're frequently writing unit tests as TDD, this is very useful.


It's also easy to integrate with IDEs or editors, for example IntelliJ IDEA, Eclipse(GGTS/STS), Sublime Text 2, Vim, and so on.



To learn more about improx plugin, please read the user guide.


Please check it out and send me your feedback!

Nov 30, 2011

GExcelAPI for Groovyist using MS Excel

Do you love Excel?

If you want to automate operations which use Excel, you can use a famous library, Apache POI. But I can't say that it's easy enough, even if using from Groovy. Especially, a identification of a cell to use an index is too complicated.

If you want to read a value of a cell labeled "A1", you must write as follows:
  1. File inputFile = ...  
  2. def book = new HSSFWorkbook(new POIFSFileSystem(new FileInputStream(inputFile)))  
  3. def sheet = book.getSheetAt(0// 1st sheet  
  4. println "A1: "   sheet.getRow(0)?.getCell((short0)  
  5. println "A2: "   sheet.getRow(1)?.getCell((short0)  
  6. println "B1: "   sheet.getRow(0)?.getCell((short1)  
...it's very difficult to read an write.

So I developed a wrapper library of Apache POI, called GExcelAPI. Version 0.2 was released at 2010-12-16. The name is very similar to "JExcelAPI" but there is no relationship. It's just a wrapper of "Apache POI".

By using GExcelAPI, you can rewrite the above sample:
  1. File inputFile = ...  
  2. def book = new HSSFWorkbook(new POIFSFileSystem(new FileInputStream(inputFile)))  
  3. def sheet = book[0// 1st sheet  
  4. println "A1: "   sheet.A1.value  
  5. println "A2: "   sheet.A2.value  
  6. println "B1: "   sheet.B1.value  
You can directly use a label of a cell to specify it. It's intuitive and obvious.

GExcelAPI v0.2 has been released on my maven repository on Github. So you can use it via Grape.
  1. @GrabResolver(name="kobo-maven-repo", root="https://github.com/kobo/maven-repo/raw/master/release")  
  2. @GrabConfig(systemClassLoader=true// necessary if you invoke it by GroovyServ  
  3. @Grab("org.jggug.kobo:gexcelapi:0.2")  
  4. import org.jggug.kobo.gexcelapi.GExcel  
  5.   
  6. def book = GExcel.open(args[0])  
  7. def sheet = book[0]  
  8. println sheet.A1.value  

If you like GExcelAPI, check it out at the github.

To tell the truth, I'm not using Excel so much recently. So I hope that someone who are usually using GExcelAPI would become a committer of GExcelAPI ;-)


Oct 24, 2011

Invoking Groovy Script Directly on Vim using quickrun.vim and GroovyServ

There is an excellent vim plugin, quickrun.vim.

It makes your trial and error cycle much faster. It makes your script edited on vim invoke by shortcut keys. It's very useful for writing a script.

The plugin supports many programming languages including Groovy. But still the original Groovy command has the weak point; the starting-up of invocation is slow. Your "flow" or "zone" is interrupted by each invocation. But now, there is GroovyServ for you. It's very easy to configure your vim to use GroovyServ's groovyclient instead of original Groovy's command. Add the following lines at .vimrc:
  1. let g:quickrun_config = {}  
  2. let g:quickrun_config.groovy = {'command' : 'groovyclient'}  
Of course, GroovyServ must be installed and groovyclient must be added into PATH environment variables.

The default key bind to run a script is <Leader>r. If you want to modify it, add the following lines:
  1. let g:quickrun_no_default_key_mappings = 1  
  2. nmap <Leader>r <Plug>(quickrun)  
In my configuration, the <Leader> is a comma. So, when I input the keys of ",r", quickrun.vim works.

If you run a script by quickrun.vim first, a groovyserver's preparation might take several seconds. The starting-up messages aren't emitted to a result buffer, so you might think it's a freeze, but it's still working.
If you invoke groovyserver explicitly before you use quickrun.vim, the first invocation of quickrun.vim will be quite fast.

BTW, there are scripts which doesn't work well with GroovyServ. If your script is so, use original Groovy command on your terminal.

Enjoy your Groovy and Vim life!

Jul 29, 2011

High-speed start-up Jython/Clojure by GroovyServ

GroovyServ:
https://github.com/kobo/groovyserv

GroovyServ made a start-up time of the invocation of Groovy script very quick. However, it can be used not only for Groovy but for all JVM languages, e.g. Scala, Jython and Clojure, etc.

On Linux, when setting the following aliases, You can enjoy the power of GroovyServ for Jython:
  1. alias gython="groovyclient -cp /tmp/jython.jar -e 'import org.python.util.jython; jython.main(args)' --"  
  1. $ time jython -c "print('Hello')"  
  2. Hello  
  3.   
  4. real    0m2.503s  
  5. user    0m2.891s  
  6. sys     0m0.431s  
  7.   
  8. $ time jython -c "print('Hello')"  
  9. Hello  
  10.   
  11. real    0m2.613s  
  12. user    0m2.889s  
  13. sys     0m0.435s  
  14.   
  15. $ time gython -c "print('Hello')"  
  16. Hello  
  17.   
  18. real    0m0.959s  
  19. user    0m0.001s  
  20. sys     0m0.003s  
  21.   
  22. $ time gython -c "print('Hello')"  
  23. Hello  
  24.   
  25. real    0m1.156s  
  26. user    0m0.001s  
  27. sys     0m0.003s  

Gython(Jython + GroovyServ) is faster by one second than normal Jython. In the above way, the overhead which groovyclient passes the classpath of the additional jython.jar to groovyserver at each invocation is so large. You can do it still faster by starting groovyserver with CLASSPATH environment variable which has jython.jar.

  1. $ alias gython="groovyclient -e 'import org.python.util.jython; jython.main(args)' --"  
  2. $ export CLASSPATH=/tmp/jython.jar  
  3. $ groovyserver -r  
  1. $ time gython -c "print('Hello')"  
  2. Hello  
  3.   
  4. real    0m0.909s  
  5. user    0m0.001s  
  6. sys     0m0.002s  
  7.   
  8. $ time gython -c "print('Hello')"  
  9. Hello  
  10.   
  11. real    0m0.076s  
  12. user    0m0.001s  
  13. sys     0m0.003s  
  14.   
  15. $ time gython -c "print('Hello')"  
  16. Hello  
  17.   
  18. real    0m0.045s  
  19. user    0m0.001s  
  20. sys     0m0.003s  
Yeah!

Notice 1: I can't assure that a testing framework or a complex library works well. Do it by your self-responsibility ;-)

Notice 2: If your OS is Windows, use Groovy and GroovyServ which are installed from Zip archives. I experienced a trouble by using them of Windows-installer of version 1.8.0.

Examples in my .bashrc

  1. alias glojureserver="env CLASSPATH=/usr/local/Cellar/clojure/1.2.0/clojure.jar groovyserver"  
  2. alias glojure="dgroovyclient -e 'import clojure.main;main.main(args)' --"  
  3. alias gythonserver="env CLASSPATH=/usr/local/Cellar/jython/2.5.2/libexec/jython.jar groovyserver"  
  4. alias gython="groovyclient -e 'import org.python.util.jython; jython.main(args)' --"  
  5. alias jvmserver="env CLASSPATH=/usr/local/Cellar/jython/2.5.2/libexec/jython.jar:/usr/local/Cellar/clojure/1.2.0/clojure.jar groovyserver"  
Usage:
  1. $ glojureserver -r -v  
  2. Groovy command path: /usr/local/bin/groovy (found at PATH)  
  3. GroovyServ home directory: /usr/local/Cellar/groovyserv/0.7/libexec  
  4. Original classpath: /usr/local/Cellar/clojure/1.2.0/clojure.jar  
  5. GroovyServ default classpath: /usr/local/Cellar/clojure/1.2.0/clojure.jar:/usr/local/Cellar/groovyserv/0.7/libexec/lib/*  
  6. Killed groovyserver of 56789(1961)  
  7. Restarting groovyserver  
  8. Starting....  
  9. groovyserver 59802(1961) is successfully started  
  10.   
  11. $ time glojure -e "(println 'Hello)"  
  12. Hello  
  13.   
  14. real    0m0.867s  
  15. user    0m0.001s  
  16. sys     0m0.004s  
  17.   
  18. $ time glojure -e "(println 'Hello)"  
  19. Hello  
  20.   
  21. real    0m0.053s  
  22. user    0m0.001s  
  23. sys     0m0.004s  
  24.   
  25. $ gythonserver -r -v  
  26. Groovy command path: /usr/local/bin/groovy (found at PATH)  
  27. GroovyServ home directory: /usr/local/Cellar/groovyserv/0.7/libexec  
  28. Original classpath: /usr/local/Cellar/jython/2.5.2/libexec/jython.jar  
  29. GroovyServ default classpath: /usr/local/Cellar/jython/2.5.2/libexec/jython.jar:/usr/local/Cellar/groovyserv/0.7/libexec/lib/*  
  30. Killed groovyserver of 59802(1961)  
  31. Restarting groovyserver  
  32. Starting....  
  33. groovyserver 59938(1961) is successfully started  
  34.   
  35. $ time gython -c "print('Hello')"  
  36. Hello  
  37.   
  38. real    0m1.540s  
  39. user    0m0.001s  
  40. sys     0m0.004s  
  41.   
  42. $ time gython -c "print('Hello')"  
  43. Hello  
  44.   
  45. real    0m0.108s  
  46. user    0m0.001s  
  47. sys     0m0.003s  
  48.   
  49. $ time gython -c "print('Hello')"  
  50. Hello  
  51.   
  52. real    0m0.057s  
  53. user    0m0.001s  
  54. sys     0m0.004s  

Dec 25, 2009

Sort by Multiple Keys in Groovy

kobo-commons@github

Problem (or limit) of the Groovy's original sort methods


You can sort collections, arrays, iterators and maps by a single key using only Groovy Core API, as follows:
  1. assert [12345] == [53142].sort{ it }  
It's very useful. I like this methods.

Now, when the following Person class and instances are given, it assumes that you want to sort some list of people ordered by lastName and familyName.
  1. class Person {  
  2.     def lastName, familyName  
  3. }  
  4. def aa1 = new Person(lastName:'aa', familyName:1// Are these strange names? Never mind!  
  5. def aa2 = new Person(lastName:'aa', familyName:2)  
  6. def b1  = new Person(lastName:'b',  familyName:1)  
  7. def b2  = new Person(lastName:'b',  familyName:2)  
  8. def c1  = new Person(lastName:'c',  familyName:1)  
  9. def c2  = new Person(lastName:'c',  familyName:2)  
  10. def c3  = new Person(lastName:'c',  familyName:3)  

In the following sample, it seems to work as you expected.
  1. def people = [b2, c2, c3, b1, c1]  
  2. assert [b1, b2, c1, c2, c3] == people.sort{ [ it.lastName, it.familyName ] }  
  3.                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
  4.                                           a list in closure has multiple keys  
But it's just accidental.

See the following sample code. Do you think that Groovy’s original sort works as we expected?
  1. // our expected result  
  2. def people = [c3, aa1, b2, c1, b1, aa2, c2]  
  3. assert [aa1, aa2, b1, b2, c1, c2, c3] == people.sort{ [ it.lastName, it.familyName ] }  

The answer is NO. This code throws an AssertionException. Groovy’s sort method returns a list like the following:
  1. // actual result.  
  2. def people = [c3, aa1, b2, c1, b1, aa2, c2]  
  3. assert [b1, b2, c1, c2, c3, aa1, aa2] == people.sort{ [ it.lastName, it.familyName ] }  
  4.                            ^^^^^^^^^^  

The reason is as follows. The original sort logic is finally based on the value of Object#hashCode(), when the object doesn't implement a Comparable interface.
  1. // groovy.util.OrderBy  
  2. public int compare(T object1, T object2) {  
  3.     for (Closure closure : closures) {  
  4.         Object value1 = closure.call(object1);  
  5.         Object value2 = closure.call(object2);  
  6.         if (value1 == value2) {  
  7.             continue;  
  8.         }  
  9.         if (value1 == null) {  
  10.             return -1;  
  11.         }  
  12.         if (value1 instanceof Comparable) {  
  13.             Comparable c1 = (Comparable) value1;  
  14.             int result = c1.compareTo(value2);  
  15.             if (result == 0) {  
  16.                 continue;  
  17.             } else {  
  18.                 return result;  
  19.             }  
  20.         }  
  21.         if (value1.equals(value2)) {  
  22.             continue;  
  23.         }  
  24.         return value1.hashCode() - value2.hashCode(); // hashCode!!!  
  25.     }  
  26.     return 0;  
  27. }  
The value of "aa".hashCode() is larger than the value of "b".hashCode(), so you've gotten the above result.
This behavior confuses us very much.


Our Solution


We provide the sort methods which can sort rightly by multiple keys.

kobo-commons@github

Sample codes are as follows:
  1. import org.jggug.kobo.commons.lang.CollectionUtils  
  2. CollectionUtils.extendMetaClass()  
  3. def people = [c3, aa1, b2, c1, b1, aa2, c2]  
  4. assert [aa1, aa2, b1, b2, c1, c2, c3] == people.sort([ { it.lastName }, { it.familyName } ])  
  5. assert [aa1, aa2, b1, b2, c1, c2, c3] == people.sort({ it.lastName }, { it.familyName })  
  6. assert [aa1, aa2, b1, b2, c1, c2, c3] == people.sort { it.lastName }, { it.familyName }  
  7. assert [aa1, aa2, b1, b2, c1, c2, c3] == people.sort { it.lastName } { it.familyName }  

You can use the API as utility, too:
  1. import org.jggug.kobo.commons.lang.CollectionUtils as CU  
  2. def people = [c3, aa1, b2, c1, b1, aa2, c2]  
  3. assert [aa1, aa2, b1, b2, c1, c2, c3] == CU.sort(people, [ { it.lastName }, { it.familyName } ])  
  4. assert [aa1, aa2, b1, b2, c1, c2, c3] == CU.sort(people, { it.lastName }, { it.familyName })  

Note


We found that a useful API for this idea of sorting by multiple keys is already prepared as a constructor of groovy.util.OrderBy. But it isn’t used. Why?

Dec 15, 2009

Generating Proper equals() and hashCode() by @Equiv Annotations

We've released a small Groovy library named "kobo-commons" which has some convenience features for Groovy programming.


@Equiv annotation is one of the features.

If you annotate fields by @Equiv annotations, you can dynamically generate
proper equals() and hashCode() using specified fields.


If you wrote the following groovy code:
  1. class Sample {  
  2.     @Equiv  
  3.     String name  
  4.   
  5.     @Equiv  
  6.     String value  
  7.   
  8.     String ignored  
  9. }  

then you could use equals method and hashCode method:
  1. def s1 = new Sample(name:'John', value:'Good', ignored:'Garbage')  
  2. def s2 = new Sample(name:'John', value:'Good', ignored:'Gold')  
  3. def s3 = new Sample(name:'John', value:'Bad',  ignored:'Garbage')  
  4. def s4 = new Sample(name:'Mike', value:'Good', ignored:'Garbage')  
  5.       
  6. assert s1 == s1  
  7. assert s1 == s2  
  8. assert s1 != s3  
  9. assert s1 != s4  
  10.       
  11. assert s1.hashCode() == s1.hashCode()  
  12. assert s1.hashCode() == s2.hashCode()  
  13. assert s1.hashCode() != s3.hashCode()  
  14. assert s1.hashCode() != s4.hashCode()  


I think it's useful for entities, etc. You can keep your classes very simple.