カウンタ付きクロージャ
LL Golf のラストでshinh先生がおっしゃっていたことを受けて呼ばれた回数を内外から参照できるクロージャというのを実現できないかと試行錯誤した結果↓
ExpandoMetaClass.enableGlobally() ({ def loopCounts = [:] def getProp = { String name -> def c = delegate.class if(name == '_') return loopCounts[c] def m = c.metaClass.methods.find{ it.name =~ "get(?i)$name" } if(!m) throw new MissingPropertyException(name, c) m.invoke(delegate) } Closure.metaClass.invokeMethod = { String name, args -> def c = delegate.class if(name == 'doCall'){ args = args ?: (Object[]) [null] // prevents redundant doCall loopCounts[c] = loopCounts[c]?.next() ?: 0 delegate.resolveStrategy = Closure.TO_SELF c.metaClass.getProperty = getProp } c.metaClass.getMetaMethod(name, args).invoke(delegate, args) } })() cl = { _ } assert [cl(), cl(), cl(), cl._] == [0, 1, 2, 2] assert 'hoge'.collect{ [(it): (0.._).collect{ _ }] } == [["h":[0]], ["o":[1, 2]], ["g":[3, 4, 5]], ["e":[6, 7, 8, 9]]]
一応動くようだがマズイ副作用があるかも。getProp の後半辺りが特に怪しい。
*1:Rubiniusの力でも借りないと無理?