====== Groovy Meta Programming ======
* [[http://www.infoq.com/presentations/groovy-compile-metaprogramming|Compile-time Metaprogramming with Groovy]]
===== GroovyInterceptable =====
* Groovy 객체가 [[http://docs.groovy-lang.org/latest/html/api/groovy/lang/GroovyInterceptable.html|GroovyInterceptable]]을 구현하고 있다면 모든 메소드 호출시 메소드의 존재 여부와 상관없이 항상 ''invokeMethod''가 호출된다. Groovy 코드를 직접 작성할 때 사용가능.
* ''GroovyInterceptable''을 구현하지 않고 ''invokeMethod''만 구현했다면,
* 존재하지 않는 메소드에 대해서만 ''invokeMethod'' 호출
* 존재하지 않는 메소드 호출시 ''invokeMethod'' 없으면 ''missingMethod'' 호출
* 객체 ''MetaClass''에 ''invokeMethod'' 구현하면 메소드의 존재 여부와 상관없이 항상 ''invokeMethod'' 호출
===== MetaClass Interception =====
* Java class나 직접 작성하지 않고 의존하는 외부 Groovy class 등에 대한 interception 가능.
* 메소드 존재 여부와 상관없이 항상 호출됨.
YourClass.metaClass.invokeMethod = { String methodName, methodArgs ->
//구현
// 객체 자신을 가리킬 때는 delegate 를 사용한다. closure 이기 때문.
// 존재하지 않는 메소드 호출을 metaClass.invokeMissingMethod() 에 위임시킬 수 있다.
// invokeMissingMethod는 다시 missingMethod()에 위임한다.
}
===== ExpandoMetaClass =====
* [[http://docs.groovy-lang.org/latest/html/api/groovy/lang/ExpandoMetaClass.html|ExpandoMetaClass]] : Groovy Meta Programming의 핵심 클래스
// 아래처럼 metaClass에 메소드를 추가해줘야 metaClass 구현체가 ExpandoMetaClass로 변경됨.
Integer.metaClass.invokeMethod = { String name, args -> /* */ }
println Integer.metaClass.getClass().name // ExpandoMetaClass
==== 대량의 메소드 추가 기법 ====
Integer.metaClass {
// 메소드 추가
daysFromNow = { ->
Calendar today = Calendar.instance
today.add(Calendar.DAY_OF_MONTH, delegate)
today.time
}
// 프라퍼티 추가. 괄호없이 호출가능.
getDaysFromNow = { ->
Calendar today = Calendar.instance
today.add(Calendar.DAY_OF_MONTH, delegate)
today.time
}
// static method 추가
'static' {
isEven = { val -> val % 2 == 0 }
}
// 생성자 추가
constructor = { Calendar calendar ->
new Integer(calendar.get(Calendar.DAY_OF_YEAR))
}
constructor = { int val ->
println "Intercepting constructor call"
constructor = Integer.class.getConstructor(Integer.TYPE)
constructor.newInstance(val)
}
}
println 5.daysFromNow()
println 5.daysFromNow // without parentheses
println "Is 2 even? " + Integer.isEven(2)
println "Is 3 even? " + Integer.isEven(3)
println new Integer(4)
println new Integer(Calendar.instance)