Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
match/when implemented with Groovy's GEP-3
// No commas
def a = 'tim'
def nocom = match( a ) {
when 'dave' 'Hi Dave'
when 'tim' 'Hi Tim'
otherwise 'none of the above'
}
assert nocom == 'Hi Tim'
// Commas
a = 'William'
def com = match( a ) {
when 'dave', 'Hi Dave'
when 'tim', 'Hi Tim'
otherwise 'none of the above'
}
assert com == 'none of the above'
// Lists (can't use commas)
a = [1,3]
def list = match( a ) {
when [1,2] 'One and two'
when [1,3] 'One and three'
when [2,1] 'Two and one'
}
assert list == 'One and three'
// Wildcard Lists (can't use commas)
a = [1,2,3]
def wild = match( a ) {
when [1,3,2] 'One, three and two'
when [1,_] 'One and something'
when [1,_,3] 'One, something and three'
when [1,_,_] 'One, something and something'
otherwise 'Something else'
}
assert wild == 'One, something and three'
// Closures as the when/results
String toRoman( int num ) {
match( num ) {
when { it >= 100 } { "C" + toRoman( num - 100 ) }
when { it >= 90 } { "XC" + toRoman( num - 90 ) }
when { it >= 50 } { "L" + toRoman( num - 50 ) }
when { it >= 40 } { "XL" + toRoman( num - 40 ) }
when { it >= 10 } { "X" + toRoman( num - 10 ) }
when { it >= 9 } { "IX" + toRoman( num - 9 ) }
when { it >= 5 } { "V" + toRoman( num - 5 ) }
when { it >= 4 } { "IV" + toRoman( num - 4 ) }
when { it >= 1 } { "I" + toRoman( num - 1 ) }
otherwise ""
}
}
assert "I" == toRoman( 1 )
assert "II" == toRoman( 2 )
assert "IV" == toRoman( 4 )
assert "V" == toRoman( 5 )
assert "VI" == toRoman( 6 )
assert "IX" == toRoman( 9 )
assert "X" == toRoman( 10 )
assert "XVII" == toRoman( 17 )
assert "XXXVIII" == toRoman( 38 )
assert "CCCXCIX" == toRoman( 399 )
///////////////////////////
// Implementation below...
def match( var, c ) {
new Matcher( var:var, closure:c ).match()
}
class Matcher {
def var
Closure closure
List<When> cases = []
Otherwise otherwise
def propertyMissing( name ) {
if( name == '_' ) {
new Any()
}
else {
def w = new When()
cases << w
w
}
}
def when( condition ) { cases << new When( condition:condition ) }
def when( condition, result ) { cases << new When( condition:condition, result:result ) }
def otherwise( result ) { this.otherwise = new Otherwise( result:result ) }
public match() {
closure.delegate = this
closure.resolveStrategy = Closure.DELEGATE_ONLY
closure()
def ret = cases.find {
it.condition instanceof Closure ?
it.condition( var ) :
it.condition == var
}?.result ?: otherwise?.result
ret instanceof Closure ? ret() : ret
}
}
class When {
def condition
def result
def getAt( List a ) { condition = a ; this }
def call( result ) { this.result = result }
def propertyMissing( String result ) { this.result = result }
}
class Otherwise {
def result
}
class Any {
boolean equals( other ) { true }
}
@antsmartian

This comment has been minimized.

Copy link

commented Aug 1, 2012

+1 Nice... Will look into this and will try to write a similar one for understanding how it works :D

@antsmartian

This comment has been minimized.

Copy link

commented Aug 2, 2012

Can you explain me how the call :

when 'dave' 'Hi Dave' working?

There is a method declaration for when in the class with one parameter condition. And also you have propertyMissing in class When. My question is how does :

when 'dave' 'Hi Dave'

Is calling when method first and then propertyMissing. I'm bit confused!

@timyates

This comment has been minimized.

Copy link
Owner Author

commented Aug 2, 2012

@antoaravinth The GEP-3 Groovy parser sees this:

when 'dave' 'Hi Dave'

as:

when( 'dave' ).'Hi Dave'

So it calls propertyMissing on the When object to set the required result :-)
which creates a new When object (adding it to our list)

@antsmartian

This comment has been minimized.

Copy link

commented Aug 2, 2012

Oh! That sounds good. Thanks for your reply mate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.