In Groovy we can invoke an implicit call()
method on a Groovy object. We can leave out the call
method name and just use ()
. We can use meta programming to add an implementation for the call()
method to a class. In the following example script we add an implementation for the call()
method with a single parameter to the String
class. The implementation returns the element found at the range specified by the argument when we invoke the method:
1 2 3 4 5 6 7 8 9 | String.metaClass.call = { range -> delegate[range] } def value = 'Groovy is Gr8' assert value( 0 ) == 'G' assert value( 10 ) == 'G' assert value( 4 ) == value[ 4 ] assert value.call( 1 ) == value( 1 ) assert value( 0 .. 5 ) == 'Groovy' |
Inspired by the examples http://groovyconsole.appspot.com/view.groovy?id=21006 and http://groovyconsole.appspot.com/script/21005 we can also write our own class and implement the call()
method. This can for example be used in DSLs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class StringConverter { def value def value(s) { value = s this } /** Convert characters in value property if cond is true */ def upper(cond) { value = value. collect { cond(it) ? it.toUpperCase() : it }. join () } def call(callable) { callable } } def converter = new StringConverter() converter.with { value 'mrhaki' upper { it < 'm' } // Equivalent to: // value('mrhaki') upper { it < 'm' } // or // value('mrhaki').call(upper { it < 'm' }) // or // value('mrhaki').call(upper({ it < 'm' })) } assert converter.value == 'mrHAKI' converter.with { value( 'jdriven' ) upper { it == 'j' || it == 'd' } assert value == 'JDriven' } |
(Code written with Groovy 2.0.4)