Showing posts with label kobo. Show all posts
Showing posts with label kobo. Show all posts

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:
let g:quickrun_config = {}
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:
let g:quickrun_no_default_key_mappings = 1
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!

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:
assert [1, 2, 3, 4, 5] == [5, 3, 1, 4, 2].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.
class Person {
    def lastName, familyName
}
def aa1 = new Person(lastName:'aa', familyName:1) // Are these strange names? Never mind!
def aa2 = new Person(lastName:'aa', familyName:2)
def b1  = new Person(lastName:'b',  familyName:1)
def b2  = new Person(lastName:'b',  familyName:2)
def c1  = new Person(lastName:'c',  familyName:1)
def c2  = new Person(lastName:'c',  familyName:2)
def c3  = new Person(lastName:'c',  familyName:3)

In the following sample, it seems to work as you expected.
def people = [b2, c2, c3, b1, c1]
assert [b1, b2, c1, c2, c3] == people.sort{ [ it.lastName, it.familyName ] }
                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                          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?
// our expected result
def people = [c3, aa1, b2, c1, b1, aa2, c2]
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:
// actual result.
def people = [c3, aa1, b2, c1, b1, aa2, c2]
assert [b1, b2, c1, c2, c3, aa1, aa2] == people.sort{ [ it.lastName, it.familyName ] }
                           ^^^^^^^^^^

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.
// groovy.util.OrderBy
public int compare(T object1, T object2) {
    for (Closure closure : closures) {
        Object value1 = closure.call(object1);
        Object value2 = closure.call(object2);
        if (value1 == value2) {
            continue;
        }
        if (value1 == null) {
            return -1;
        }
        if (value1 instanceof Comparable) {
            Comparable c1 = (Comparable) value1;
            int result = c1.compareTo(value2);
            if (result == 0) {
                continue;
            } else {
                return result;
            }
        }
        if (value1.equals(value2)) {
            continue;
        }
        return value1.hashCode() - value2.hashCode(); // hashCode!!!
    }
    return 0;
}
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:
import org.jggug.kobo.commons.lang.CollectionUtils
CollectionUtils.extendMetaClass()
def people = [c3, aa1, b2, c1, b1, aa2, c2]
assert [aa1, aa2, b1, b2, c1, c2, c3] == people.sort([ { it.lastName }, { it.familyName } ])
assert [aa1, aa2, b1, b2, c1, c2, c3] == people.sort({ it.lastName }, { it.familyName })
assert [aa1, aa2, b1, b2, c1, c2, c3] == people.sort { it.lastName }, { it.familyName }
assert [aa1, aa2, b1, b2, c1, c2, c3] == people.sort { it.lastName } { it.familyName }

You can use the API as utility, too:
import org.jggug.kobo.commons.lang.CollectionUtils as CU
def people = [c3, aa1, b2, c1, b1, aa2, c2]
assert [aa1, aa2, b1, b2, c1, c2, c3] == CU.sort(people, [ { it.lastName }, { it.familyName } ])
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:
class Sample {
    @Equiv
    String name

    @Equiv
    String value

    String ignored
}

then you could use equals method and hashCode method:
def s1 = new Sample(name:'John', value:'Good', ignored:'Garbage')
def s2 = new Sample(name:'John', value:'Good', ignored:'Gold')
def s3 = new Sample(name:'John', value:'Bad',  ignored:'Garbage')
def s4 = new Sample(name:'Mike', value:'Good', ignored:'Garbage')
    
assert s1 == s1
assert s1 == s2
assert s1 != s3
assert s1 != s4
    
assert s1.hashCode() == s1.hashCode()
assert s1.hashCode() == s2.hashCode()
assert s1.hashCode() != s3.hashCode()
assert s1.hashCode() != s4.hashCode()


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