Smalltalk/Objective-C method calls in Groovy – @AsMessage AST transformation

I like method call (or message passing syntaxis) in Objective-C (inspired by Smalltalk). You can achieve more readable code that can be read like a natural language (taken from OCMock tests):

[mock stringByPaddingToLength:20 withString:@"foo" startingAtIndex:5];

In my current customer project we mock/stub some methods through metaclass or by using Grails mocks. (Spock up to 0.6 version is not able to mock neither dynamic nor static methods). To improve test code readability, I extract mock creation and configuration into a separate helper method:

def mockAddChargeOn(args, order) {
    order.metaClass.addChargeCalled = false
    order.metaClass.addCharge = { actualAmount, actualDueDate ->
        order.addChargeCalled = true
        assert actualAmount == args.expectsAmount
        assert actualDueDate == args.expectsDueDate

so I can mock addCharge like this:

mockAddChargeOn order, expectsAmount: 1.0, expectsDueDate: tomorrow(), returns: aCharge

As you can see, I use named parameters extensively. Their drawback is lack of documentation through method signature. You have to read through the method body or rely on your IDE. IntelliJ IDEA is smart enough to figure out which named parameters a method supports and shows them in code completion. But not everybody uses this IDE.

I came up with a solution based on an AST transformation. If you annotate a method with @AsMessage, the transformation adds a new method with named parameters calling the original method:

def mockAddChargeOn(order, expectsAmount, expectsDueDate, returns)

// Added by the AST transformation
def mockAddChargeOn(args, order) {
    mockAddChargeOn order, args.expectsAmount, args.expectsDueDate, args.returns

Your methods have clear signatures and you can call them using a more fluent syntax.

You find the source code and full documentation on GitHub:

If you are brave enough to test it out, spot a bug or want a new feature, use GitHub issues. Or you catch me on Twitter (@mgryszko).

Final note

I’m not going to apply this transformation on public API. My ‘target group’ is initially test code. The transformation should not substitute short method signatures with few parameters. Keep in mind than long signatures make method difficult to understand (Steve McConnell in Code Complete recommends using less than seven parameters; Robert C. Martin in Clean Code reduces this number to three).