Tuesday 26 January 2010

Issues with Eclipse 3.5.1 and groovy plug-in

For all you Linuxy peeps.

After installing Eclipse 3.5.1 (SDK version) I installed all the plugins I usually use but when I installed the groovy v2 plugin all my existing plugins disappeared along with the groovy one. Eclipse insisted that they were installed but they weren't there.

It seems that this combination doesn't like "shared installs". My eclipse installation was in /usr/local/eclipse and I was installing the groovy plugin as my regular user. Fail.

There are two solutions.

1 - install a local copy of eclipse.

Simple but it means an eclipse install per user on your machine.

2 - install the groovy plugin as root.

Means that you have to run it as root every time you want to upgrade the plugin.

Choose whichever evil is lesser for you. (I chose #2).

BTW you may also need this magic shell script line

export GDK_NATIVE_WINDOWS=true

if you find that some of the buttons in eclipse don't like being clicked on. Apparently this is due to be fixed in eclipse 3.5.2.

Hope this saves someone a few frustrated hours.


Friday 8 January 2010

Ham and Chips

Rob Fletcher's blog post on gMock inspired me to try out hamcrest, but I was surprised to find out there's no simple way to match collections in mocked method arguments - the best I could come up with was this...
mock(tagLib).fieldLabel(instanceOf(Map), instanceOf(Closure)).returns("<label></label>")
which doesn't tell me whether I'm calling fieldLabel with the expected attributes. After a bit of searching I found the MapContentMatcher in the Spring Integration library, but didn't want include the whole jar just for that. It also had dependencies other libraries and was heavily typed with generics. Here's the cut down groovy version...
import org.hamcrest.*
import static org.hamcrest.core.AllOf.*
import org.hamcrest.Factory as HamcrestFactory

class MapContentMatcher extends TypeSafeDiagnosingMatcher<Map> {

Object key
Object value

MapContentMatcher(Object key, Object value) {
this.key = key
this.value = value
}

public boolean matchesSafely(Map actual, Description mismatchDescription) {
return actual.containsKey(key) && value == actual[key]
}

public void describeTo(Description description) {
description.appendText("$key:$value")
}

@HamcrestFactory
public static Matcher hasAllEntries(Map expected) {
return allOf(expected.collect { k, v ->
new MapContentMatcher(k, v)
})
}
}

Which can be used thus...
mock(tagLib).fieldLabel(hasAllEntries([id: expectedField, label:expectedHeading]), instanceOf(Closure)).returns("<label></label>")

Thursday 7 January 2010

Sitemesh layout applied to AJAX response (gotcha)

Grails supports multiple ways to specify a sitemesh layout for your responses. One way I wasn't familiar with is by convention, i.e. if you have a controller 'BookController' and a layout in /views/layouts called book.gsp all the actions in BookController will be rendered with the book layout by default - even if you do render("some text") or render(template: "/sometemplate").

So if you're wondering why all your AJAX responses are getting wrapped up in a sitemesh template this could be the reason. You can stop this by changing the content type to text/plain or by renaming the layout and specifying it explicitly in your gsps using <meta name="layout" content="layoutname"/>.