//----------------------------------------------------------------------------------
// you want a private persistent variable within a script method
// you could use a helper class for this
class CounterHelper {privatestaticcounter = 0defstatic next(){ ++counter }}defgreeting(s){defn = CounterHelper.next()
println "Hello $s (I have been called $n times)"}
greeting('tom')
greeting('dick')
greeting('harry')// =>
// Hello tom (I have been called 1 times)
// Hello dick (I have been called 2 times)
// Hello harry (I have been called 3 times)
// you could make it more fancy by having separate keys,
// using synchronisation, singleton pattern, ThreadLocal, ...
//----------------------------------------------------------------------------------

//----------------------------------------------------------------------------------
// Determining Current Method Name
// Getting class, package and static info is easy. Method info is just a little work.
// From Java we can use:
// new Exception().stackTrace[0].methodName
// or for Java 5 and above (saves relatively expensive exception creation)
// Thread.currentThread().stackTrace[3].methodName
// But these give the Java method name. Groovy wraps its own runtime
// system over the top. It's still a Java method, just a little bit further up the
// stack from where we might expect. Getting the Groovy method name can be done in
// an implementation specific way (subject to change as the language evolves):
def myMethod(){
names = newException().stackTrace*.methodName
println groovyUnwrap(names)}defmyMethod2(){
names = Thread.currentThread().stackTrace*.methodName
names = names[3..<names.size()]// skip call to dumpThread
println groovyUnwrap(names)}defgroovyUnwrap(names){ names[names.indexOf('invoke0')-1]}
myMethod()// => myMethod
myMethod2()// => myMethod2
// Discussion: If what you really wanted was a tracing mechanism, you could overrie
// invokeMethod and print out method names before calling the original method. Or
// you could use one of the Aspect-Oriented Programming packages for Java.
//----------------------------------------------------------------------------------

//----------------------------------------------------------------------------------
// Prototyping Functions: Not supported by Groovy but arguably
// not important given other language features.
// Omitting Parentheses Scenario: Groovy only lets you leave out
// parentheses in simple cases. If you had two methods sum(a1,a2,a3)
// and sum(a1,a2), there would be no way to indicate that whether
// 'sum sum 2, 3, 4, 5' meant sum(sum(2,3),4,5) or sum(sum(2,3,4),5).
// You would have to include the parentheses. Groovy does much less
// auto flattening than some other languages; it provides a *args
// operator, varargs style optional params and supports method
// overloading and ducktyping. Perhaps these other features mean
// that this scenario is always easy to avoid.
def sum(a,b,c){ a+b+c*2}defsum(a,b){ a+b }// sum sum 1,2,4,5
// => compilation error
sumsum(1,2),4,5
sum sum(1,2,4),5// these work but if you try to do anything fancy you will run into trouble;
// your best bet is to actually include all the parentheses:
println sum(sum(1,2),4,5)// => 17
println sum(sum(1,2,4),5)// => 16
// Mimicking built-ins scenario: this is a mechanism to turn-off
// auto flattening, Groovy only does flattening in restricted circumstances.
// func(array, 1, 2, 3) is never coerced into a single list but varargs
// and optional args can be used instead
def push(list, Object[]optionals){
optionals.each{ list.add(it)}}
items = [1,2]
newItems = [7, 8, 9]
push items, 3, 4
push items, 6
push (items, *newItems)// brackets currently required, *=flattening
// without *: items = [1, 2, 3, 4, 6, [7, 8, 9]]
assert items == [1, 2, 3, 4, 6, 7, 8, 9]//----------------------------------------------------------------------------------

//----------------------------------------------------------------------------------
// Saving Global Values
// We can just save the value and restore it later:
defprintAge(){ println "Age is $age"}
age = 18// binding "global" variable
printAge()// => 18
if(age > 0){deforigAge = age
age = 23
printAge()// => 23
age = origAge
}
printAge()// => 18
// Depending on the circmstances we could enhance this in various ways
// such as synchronizing, surrounding with try ... finally, using a
// memento pattern, saving the whole binding, using a ThreadLocal ...
// There is no need to use local() for filehandles or directory
// handles in Groovy because filehandles are normal objects.
//----------------------------------------------------------------------------------