13

What does this syntax mean in Groovy?

class CreateMessagePage extends Page {
    static at = { assert title == 'Messages : Create'; true }
    static url = 'messages/form'
    static content =  {
        submit { $('input[type=submit]') }
        MyVeryStrangeForm { $('form') }
        errors(required:false) { $('label.error, .alert-error')?.text() }
    }
}

(taken from Spring MVC Test HtmlUnit manual)

The question is about Groovy and I would like know the answer in Groovy terms.

What is content? Is it a static variable? Is its name is random or predefined by base class of Page?

What is = (equal sign) after it? Is it an assignment operator?

What is at the right hand side of =? Is this a closure? Or if this an anonymous class? Or if these are the same?

What is submit inside curly braces?

Is this a variable? Why there is no assignment operator after it then?

Is this a function definition? Can I define functions in arbitrary places in Groovy? If this is a function definition, then what is errors then?

Is submit is a function call, receiving { $('input[type=submit]') } as a parameter? If yes, then where is this function can be defined? For example, where is MyVeryStrangeForm defined (is nowhere)?

If this was function call, then it won't work since it's undefined...

Wilfred Hughes
  • 29,846
  • 15
  • 139
  • 192
Dims
  • 47,675
  • 117
  • 331
  • 600

1 Answers1

19

Quick answer to all questions: it's a block of code, like anonymous function, called closure in Groovy.

See http://www.groovy-lang.org/closures.html

In Groovy you can reference/pass/set such closure, as in any Functional Language.

So this:

static at = { assert title == 'Messages : Create'; true }

means that class field at will be set to this closure (notice, not result of closure execution, but closure itself, as block of code). Type of at is omitted there, but it could be static def at or static Object at, or static Closure at

This code could be executed anytime later, in different context, with title defined, etc.

This:

submit { $('input[type=submit]') }

means calling a function submit with closure as argument.

If you want to write own function like this, it should be something like:

def submit(Closure code) {
    code.call()
}

Brackets could be omitted, so it could be written as submit({$('input[type=submit]')}). Same for other function as well, it could be println 'hello world!' instead of println('hello world').

There's also a common practice to define closure as last argument, like:

def errors(Map opts, Closure code) {
  ....
}

at this case you could pass first arguments as usual, wrapped in brackets, and closure outside:

errors(required:false) { ...... }

same to:

errors([required: false], { ..... })
Freek de Bruijn
  • 3,552
  • 2
  • 22
  • 28
Igor Artamonov
  • 35,450
  • 10
  • 82
  • 113
  • By why it didn't written `form = { $('form') }` but `form { $('form') }`, i.e. without assignment? – Dims Jan 07 '16 at 16:55
  • I mean I would understand this if it would always written "as in any functional language" – Dims Jan 07 '16 at 16:56
  • This is not calling function because I am allowed to write my own names there! – Dims Jan 07 '16 at 16:57
  • you should _delegate_ them into closure, please read link to official docs – Igor Artamonov Jan 07 '16 at 17:03
  • Are you absolutely sure it is function call? May be it is some Geb DSL? – Dims Jan 07 '16 at 17:09
  • what's the difference? Groovy DSL is usually done through closures and functions calls. So it's both, DSL _and_ function call – Igor Artamonov Jan 07 '16 at 17:13
  • I don't understand how it can be function call if I can use arbitrary name. Where the function is defined? There are all possible function names pre-defined in Groovy somewhere? – Dims Jan 07 '16 at 17:15
  • oh, i see, you mean where this `submit` are defined? I guess this ones just catched by `methodMissing` of the closure delegate – Igor Artamonov Jan 07 '16 at 17:20
  • 1
    just checked sources: https://github.com/geb/geb/blob/master/module/geb-core/src/main/groovy/geb/content/PageContentSupport.groovy that's true, this is processed by `methodMissing` – Igor Artamonov Jan 07 '16 at 17:22
  • So this is a call to undefined function, which is processed in special way by base class? – Dims Jan 07 '16 at 17:25
  • 1
    yes, in groovy you can handle call of non existing function. – Igor Artamonov Jan 07 '16 at 17:32