I am wondering what is the groovy way to accomplish something similar to Python's context manager, with it's init, enter and exit methods. Here is the basic example in Python:
class ContextManager():
def __init__(self):
print('init method called')
def __enter__(self):
print('enter method called')
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
print('exit method called')
with ContextManager() as manager:
print('with statement block')
Output:
init method called
enter method called
with statement block
exit method called
If you need your own entry points, you can write your own base class to steer this behaviour.
class ContextManager {
ContextManager() { println "init" }
void enter() { println "enter" }
void exit(Throwable t=null) { println "exit ${t?:""}" }
String getInner() { "inner" }
final run(Closure f) {
try {
enter()
f(this)
exit()
}
catch (Throwable t) {
exit(t)
}
}
}
def outer = "outer"
new ContextManager().run { manager ->
println outer
println manager.inner
println "body"
}
Output:
init
enter
outer
inner
body
exit
Groovy can accomplish something similar to this for the enter and exit using metaprogramming. Groovy has both runtime and compile-time metaprogramming. With runtime metaprogramming, you could do something similar by using invokeMethod in a class.
InvokeMethod Docs
Example
Compile-time metaprogramming is a bit more difficult because you are dealing at the compiler level:
Documentation
Simple Example
I made a Grails plugin, which would be a much more complicated example, that allows me to do something similar but invoking closures around methods:
Source
Test app
Hope some of this helps...
Related
Inside a spock test we want to create a resource and make sure its disposed correctly regardless of the outcome of the test result.
We tried the approach below. But spock is not executing tests when the test code is wrapped inside a closure.
import spock.lang.Specification
class ExampleSpec extends Specification {
def wrapperFunction(Closure cl) {
try {
cl()
} finally {
// do custom stuff
}
}
def "test wrapped in closure"() {
wrapperFunction {
expect:
1 == 1
println "will not execute!"
}
}
}
What is the best approach on creating and disposing a resource inside a spock test.
setup() and cleanup() are not viable solutions since creating and disposing should be possible at arbitrary points inside the feature method.
You can use setup and cleanup block inside of the test case (feature method) like this:
class ReleaseResourcesSpec extends Specification {
void 'Resources are released'() {
setup:
def stream = new FileInputStream('/etc/hosts')
when:
throw new IllegalStateException('test')
then:
true
cleanup:
stream.close()
println 'stream was closed'
}
}
Code from the cleanup block is always executed although the test fails or if there is any exception. See the result of the above example:
So it is similar to setup() and cleanup() methods but in this case you can have different setup and clean up code for each feature method.
I'm very new to Groovy.
Very simple question about the code found in CliBuilder.
http://docs.groovy-lang.org/latest/html/gapi/index.html?overview-summary.html
def cli = new CliBuilder(name:'ls')
cli.a('display all files')
cli.l('use a long listing format')
cli.t('sort by modification time')
def options = cli.parse(args)
assert options // would be null (false) on failure
assert options.arguments() == ['*.groovy']
assert options.a && options.l && options.t
The CliBuilder class behaves as knowing whatever methods we want to call in advance. By what Groovy's feature it can be supported?
This is called Runtime metaprogramming.
If you want to create your own class with "dynamic methods", the easiest way is to implement the GroovyInterceptable interface and add the invokeMethod method to your class.
class Interception implements GroovyInterceptable {
def definedMethod() { }
def invokeMethod(String name, Object args) {
'invokedMethod'
}
}
Whenever a method is called on an instance if the class Interception, invokeMethod is called instead. Note that this is also true for methods actually defined in the class (e.g. definedMethod)
You can use the metaClass to call the actual method like this
class Interception implements GroovyInterceptable {
def definedMethod() { }
def invokeMethod(String name, Object args) {
if (name == "actualMethod") {
return metaClass.invokeMethod(this, name, args)
}
return "invokedMethod: $name($args)"
}
def actualMethod() {
return 'hello there'
}
}
Here a call to actualMethod still goes through invokeMethod, however invokeMethod contains logic to call the actual method.
There are some other ways (see link on top) to acomplish similar behavior, but I found this to be the easiest.
Note that runtime metaprogramming is incompatible with #CompileStatic unless you add a TypeCheckingExtension to mitigate this.
Run Example
Why do I need to use System.out.println instead of println when I use GroovyInterceptable?
For example if I am coding in a Groovy file I can just print to the console by typing:
println "Printing to Console"
But if I want to print here:
class Test implements GroovyInterceptable {
def sum(Integer x, Integer y) { x + y }
def invokeMethod(String name, args) {
System.out.println "Invoke method $name with args: $args"
}
}
def test = new Test()
test?.sum(2,3)
I have to use System.out.println in that method, or else I get a StackOverflowError. Why?
UPDATE:
Thanks to #Dan Getz for the answer below I know why it happens with the GroovyInterceptable class now. Does anyone know if there are other class implementations in Groovy where this issue could arise?
This is because your class Test implements the GroovyInterceptable interface, which according to the docs, is
used to notify that all methods should be intercepted through the invokeMethod mechanism of GroovyObject.
This isn't just methods that have been defined on your class. Try:
test?.total(2,3)
You'll see that it returns
Invoke method total with args: [2, 3]
The call to println inside invokeMethod is thus understood as a call to this.println, just like a call to sum would be. But this.println just calls invokeMethod again, because you implemented GroovyInterceptable, and so on.
This wouldn't happen if you didn't implement GroovyInterceptable. For example, running the following code
class Test {
def sum(Integer x, Integer y) {
println "Let's sum!"
x + y
}
}
def test = new Test()
test?.sum(2,3)
Will output
Let's sum!
I need to pass a list of methods to execute inside the class with "closure way", see the code bellow
class A{
def m1(){
println "Method1"
}
def m2(){
println "Method1"
}
def commands = { closure->
println "before"
closure.call()
println "after"
}
}
A a = new A()
a.commands{
println "before execute method m1"
m1() //A need to execute m1 method of the class A
println "after execute method m1"
}
When I comment the m1() the output is
before
before execute method m1
after execute method m1
after
otherwise throw the exception MissingMethodException: No signature of method for method m1()
So, it does not recognize the m1() method as method of class A
Depending on what you are really trying to accomplish, you may want something like this...
class A{
def m1(){
println "Method1"
}
def m2(){
println "Method1"
}
def commands(closure) {
def c = closure.clone()
c.delegate = this
println "before"
c()
println "after"
}
}
The delegate gets an opportunity to respond to method calls that are made inside of the closure. Setting the delegate to this will cause the calls to m1() to be dispatched to the instance of A. You may also be interested in setting the resolveStrategy property of the closure. Valid values for resolveStrategy are Closure.DELEGATE_FIRST, Closure.OWNER_FIRST, Closure.DELEGATE_ONLY, Closure.OWNER_ONLY. The owner is the thing that created the closure and cannot be changed. The delegate can be assigned any object. When the closure makes method calls the methods may be handled by the owner or the delegate and the resolveStrategy comes into play in deciding which to use. The names DELEGATE_ONLY, OWNER_ONLY, DELEGATE_FIRST and OWNER_FIRST I think are self explanatory. If you need any more info, let me know.
I hope that helps.
I have this class structure:
interface bug
{
def method()
}
public class A implements bug{
def method()
{
println "Works"
}
}
A varaiable = new A()
bug.metaClass.invokeMethod {
name,args ->
println "Came here"
}
varaiable.method()
when I do this, I get Works. Why not Came here?
Where I'm doing the mistake?
EDIT:
Even if I do:
A.metaClass.invokeMethod {
name,args ->
println "Came here"
}
I'm getting only Works.
You're changing the metaClass of A with
A.metaClass.invokeMethod { name,args ->
println "Came here"
}
After you construct the variable. If you put this block before the line
A varaiable = new A()
It should work as you'd expect.
To get round this, you can use:
ExpandoMetaClass.enableGlobally()
And instances will check back with the metaClass every invocation, however as expected this can slow things down