// "favor composition over inheritance" ~Effective Java
class Parent {
def getAll() {
String resp = ""
2.times {
resp += get(it)
}
return resp
}
def get(def i) {
"get PARENT $i\n"
}
}
class Child1 extends Parent {
def get(def i) {
"get CHILD $i\n" // is used by parent's getAll
}
}
class Child2 {
@Delegate Parent p = new Parent() // decorated Parent instance
def get(def i) {
"get CHILD $i\n" // not used by parent's getAll
}
}
Parent c1 = new Child1()
assert c1.getAll() == "get CHILD 0\nget CHILD 1\n" // calls child's get()
assert c1.get(0) == "get CHILD 0\n"
//Parent c2 = new Child2() // Child2 is not a Parent!
Child2 c2 = new Child2()
assert c2.getAll() == "get PARENT 0\nget PARENT 1\n" // calls parent's get()
assert c2.get(0) == "get CHILD 0\n"
Thursday, November 15, 2012
@Delegate vs. Extends
Monday, November 5, 2012
DNS lookup - timed
int maxTimeout = 30000
int minTimeout = 15000
List domainList = [
'gmail.com', 'google.co.uk', 'google.com', 'bbc.co.uk', 'cnn.com', 'java.oracle.com',
'facebook.com', 'twitter.com', 'oracle.com', 'zen.co.uk', 'java.net', 'www.scala-lang.org',
'plus.google.com', 'guardian.co.uk', 'linkedin.com', 'www.typesafe.com', 'www.yahoo.com',
'www.ibm.com', 'www.apache.org', 'www.adobe.com', 'www.microsoft.com', 'www.stackoverflow.com',
'www.apple.com', 'groovy.codehaus.org', 'java.oracle.com', 'www.telegraph.co.uk', 'www.jroller.com',
'www.dell.com', 'www.samsung.com', 'www.amazon.co.uk', 'docs.oracle.com', 'www.infoq.com',
'www.devoxx.com', 'www.qconlondon.com', 'www.smashingmagazine.com', 'en.wikipedia.com' ]
int count = 1
while (true) {
int idx = (int)( Math.random() * domainList.size )
println "[$count] nslookup ${domainList[idx]}"
def process = "nslookup ${domainList[idx]}".execute()
println "Found text ${process.text}"
int sleepTime = (int)( minTimeout + Math.random() * ( maxTimeout - minTimeout))
Thread.sleep( sleepTime );
++count
}
Monday, October 29, 2012
Resolve an HTTP Redirect
// source: https://gist.github.com/3899754
def findRealUrl(url) {
HttpURLConnection conn = url.openConnection()
conn.followRedirects = false
conn.requestMethod = 'HEAD'
if(conn.responseCode in [301,302]) {
if (conn.headerFields.'Location') {
return findRealUrl(conn.headerFields.Location.first().toURL())
} else {
throw new RuntimeException('Failed to follow redirect')
}
}
return url
}
Wednesday, August 1, 2012
match/when implemented with Groovy's GEP-3
//WOW! https://gist.github.com/3002724
// 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( v, c ) {
new Matcher( var:v, closure:c ).match()
}
class Matcher {
def var
Closure closure
List 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 }
}
println 'DONE'
Sunday, July 15, 2012
GPars DataflowQueues
//source: http://jaxenter.com/tutorial-gpars-making-parallel-systems-groovy-and-java-friendly-43529-2.html
//a sample code build process //
//source: http://jaxenter.com/tutorial-gpars-making-parallel-systems-groovy-and-java-friendly-43529-2.html
//a sample code build process //
import static groovyx.gpars.dataflow.Dataflow.operator
import groovyx.gpars.dataflow.*
def _checkout = { String a ->
Thread.sleep( (Long)Math.random() * 5 ); // a bit of random delay for fun
println ">checking out...$a"
return "checkout-$a"
}
def _compileSources = { a ->
println ">compiling...$a"
return "compileSources-$a"
}
def _generateAPIDoc = { a ->
println ">api Docs...$a"
return "generateAPIDoc-$a"
}
def _generateUserDocumentation = { a ->
println ">user Docs...$a"
return "generateUserDocumentation-$a"
}
def _packageProject = { project, api, doc ->
println ">packaging...$project $api $doc"
return "packageProject-$project $api $doc"
}
def _deploy = { a ->
println ">deploying...$a"
return (!!Math.round(Math.random()))
}
/* We need a Broadcaster and Queues to wire elements together */
def checkedOutProjects_B = new DataflowBroadcast()
def urls_Q = new DataflowQueue()
def compiledProjects_Q = new DataflowQueue()
def apiDocs_Q = new DataflowQueue()
def userDocs_Q = new DataflowQueue()
def packages_Q = new DataflowQueue()
def done_Q = new DataflowQueue()
/* Here's the composition of individual build steps into a process */
operator(inputs: [urls_Q], outputs: [checkedOutProjects_B], maxForks: 3) { url ->
bindAllOutputs _checkout(url)
}
operator([checkedOutProjects_B.createReadChannel()], [compiledProjects_Q]) { projectRoot ->
bindOutput _compileSources(projectRoot)
}
operator(checkedOutProjects_B.createReadChannel(), apiDocs_Q) { projectRoot ->
bindOutput _generateAPIDoc(projectRoot)
}
operator(checkedOutProjects_B.createReadChannel(), userDocs_Q) { projectRoot ->
bindOutput _generateUserDocumentation(projectRoot)
}
operator([compiledProjects_Q, apiDocs_Q, userDocs_Q], [packages_Q]) { project, api, doc ->
bindOutput _packageProject(project, api, doc)
}
def deployer = operator(packages_Q, done_Q) { packagedProject ->
boolean ok = _deploy(packagedProject)
println "! Deployed? $ok"
bindOutput (ok)
}
/* add data, start the machine a rollin! */
5.times { urls_Q << "url #$it" }
5.times { urls_Q << "url #${++it*5}" }
/* Now we're set up, and can just wait for the build to finish */
println "==Starting the build process. This line MIGHT NOT be printed out first ...=="
//deployer.join() //Wait for the last operator in the network to finish??
Thursday, July 12, 2012
GBench - easy code benchmarking
//source: http://nagaimasato.blogspot.jp/2012/07/gbench-031-released.html
//requires Groovy 2.0.0+
@Grab('com.googlecode.gbench:gbench:0.3.1-groovy-2.0')
import gbench.BenchmarkBuilder
import groovy.transform.CompileStatic
int fib(int n) {
if (n < 2) return n
return fib(n - 1) + fib(n - 2)
}
@CompileStatic
int fib2(int n) {
if (n < 2) return n
return fib2(n - 1) + fib2(n - 2)
}
new BenchmarkBuilder().run {
int n = 20
"Normal Version" { fib n }
"@CompileStatic Version" { fib2 n }
}.prettyPrint()
Wednesday, July 11, 2012
Conceptual Map/Reduce Example
//inspiration: http://hamletdarcy.blogspot.ca/2008/01/mapreduce-for-mere-mortals.html
// general purpose function
def mapReduceFunc = { data, mapFunction, reduceFunction ->
def mappedData = data.collect(mapFunction)
reduceFunction(mappedData)
}
// the data
Map dictionary = [
abacus: "a device for making arithmetic calculations",
arc: "any unbroken part of the circumference of a circle",
beaver: "a large, amphibious rodent of the genus Castor"
]
// the mapping function impl
def startingCharacter = { pair ->
pair.value = pair.key[0].toLowerCase()
return pair
}
// the reducing function impl
def countCharacters = { dataMap ->
Map result = [:]
('a'..'z').each{ result[it] = 0 }
dataMap.each { pair -> result[pair.value]++ }
return result
}
// put it all together!
def result1 = mapReduceFunc(dictionary, startingCharacter, countCharacters)
println result1
//// TWEAK THE I/O FUNCS! ////
// the mapping function impl
startingCharacter = { pair ->
return pair.key[0].toLowerCase()
}
// the reducing function impl
countCharacters = { dataList ->
Map result = [:]
('a'..'z').each{ result[it] = 0 }
dataList.each { it -> result[it]++ }
return result
}
// put it all together!
def result2 = mapReduceFunc(dictionary, startingCharacter, countCharacters)
println result2
assert result1 == result2
Subscribe to:
Posts (Atom)