AST transformation converting a method signature to a Smalltalk-like message
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Like Smalltalk/Objective-C message passing? Want to have a more human-readable code? Annotate your method with @AsMessage

def mockBlowOn(whistle, times, expects, returns)

and instead of:

mockBlowOn whistle, 1, 'fififi', 'pufff'

you call:

mockBlowOn whistle, times: 1, expects: 'fififi', returns: 'pufff'

How it works

@AsMessage adds a new method to the declaring class, preserving by default the first parameter and adding a named parameter map. The body of the message method calls the transformed method by passing the arguments extracted from the named parameters:

def mockBlowOn(whistle, times, expects, returns)


def mockBlowOn(Map args, whistle) { 
	mockBlowOn(whistle, args.times, args.expects, args.returns)

Parameterless and single parameter methods are not transformed.

What happens with default parameter values?

They are used as default key values if not provided in named args. First parameter's default parameter value is preserved too.

You can call:

def mockBlowOn(whistle, times = 1, expects, returns)


mockBlowOn whistle, expects: 'fififi', returns: 'pufff'

What if the transformed method has already a closure as last parameter?

It is preserved (as last parameter), with or without a default value:

def mockBlowOn(whistle, times, expects, Closure returns)

is called as:

mockBlowOn whistle, times: 1, expects: 'fififi', { 
    ['pufff', 'pafff', 'bufff']

And named parameters?

They must be provided as an explicit map in the first parameter after transformation:

def methodWithNamedParameters(args, param1, param2)

should be called as:

methodWithNamedParameters([namedParam1: 'first', namedParam2: 'second'], param1: '1', param2: 2)

And a varargs parameter?

Varargs are passed as a named parameter, either as array or list:

def mockBlowOn(whistle, times, expects, ...returns)

is called either as

mockBlowOn whistle, times: 1, expects: 'fififi', returns: ['pufff', 'pafff', 'bufff']

or with more ceremony

mockBlowOn whistle, times: 1, expects: 'fififi', returns: ['pufff', 'pafff', 'bufff'] as Object[]


Don't preserve first parameter

First parameter can optionally removed and its value taken from the named parameters. You do this by setting the preserveFirstParameter annotation parameter to false (the default value is true):

@AsMessage(preserveFirstParameter = false)
def mockBlowOn(whistle, times, expects, returns)


def mockBlowOn(Map args) { 
	mockBlowOn(args.whistle, args.times, args.expects, args.returns)

Handling of array parameters

Any array parameter of the transformed method can be provided either as array or list after transformation.

Transformation doesn't...

  • check if the it makes sense (e.g. with methods already having named parameters)
  • validate if the map with named parameters contains all arguments required to call the original method (al least not yet)