Created
June 27, 2012 09:17
-
-
Save timyates/3002724 to your computer and use it in GitHub Desktop.
match/when implemented with Groovy's GEP-3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 } | |
} |
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!
@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)
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
+1
Nice... Will look into this and will try to write a similar one for understanding how it works :D