I'm writing a small DSL for reactive evaluation, need help with metaprogramming in Groovy.
Sample DSL code:
Signal<Integer> a = var(1)
Signal<Integer> b = var(2)
Signal<Integer> c = signal { a(it) + b(it) }
The 'var' function creates new Signal instance.
The signal function needs a list of Signal instances inside the closure (references to a and b in example).
Working implementation:
interface Signal<T> {
T now()
}
Signal.metaClass.call = { dependencies ->
dependencies?.add(delegate)
delegate.now()
}
def signal = { Closure<?> body ->
def dependencies = new HashSet<>()
body.call(dependencies)
createSignal(dependencies, body)
}
Is there any way to awoit passing it variable, so sample looks like
Signal<Integer> a = var(1)
Signal<Integer> b = var(2)
Signal<Integer> c = signal { a() + b() }
EDIT:
Stub Signal implementation for testing:
class SignalStub<T> implements Signal<T> {
T value
Collection<Signal<?>> dependencies
static def var(value) { new SignalStub<>(value: value, dependencies: [])}
static def createSignal(deps, body) { new SignalStub<Object>(value: body.call(), dependencies: deps) }
#Override
T now() {
return value
}
}
Test case for DSL:
def a = var(1)
def b = var(2)
def c = signal { a() + b() }
assert c.now() == 3
assert c.dependencies.contains(a)
assert c.dependencies.contains(b)
The question is: "Is there a way to avoid passing the it variable?"
Since a and b are local variables and local variables are not taking part in the MOP, it should be impossible to do using runtime meta programming.
Using a transform it is possible, but I don't know if you want to go that far here
Related
I have a class like this:
in foo.groovy
class Foo {
String thing
Integer other
Foo(String thing) {
this.thing = thing
}
Foo(Integer other) {
this.other = other
}
}
return Foo.class
Now I would like to invoke these constructors. What I am doing is:
Other.groovy
def foo = evaluate(new File(ClassLoader.getSystemResource('foo.groovy').file)).newInstance(10)
def foo2 = evaluate(new File(ClassLoader.getSystemResource('foo.groovy').file)).newInstance("thing")
But this doesn't seem like the correct way of doing it. Ideally I would like to actually name the file Foo.groovy but then I get an error because it automatically declares the class for me. Basically, I want it to work like a classic Java class
Maybe I'm missing something here, but:
class Foo {
String thing
Integer other
Foo(String thing) {
this.thing = thing
}
Foo(Integer other) {
this.other = other
}
}
def x = new Foo(10)
assert x.other == 10 // true
def y = new Foo("foo")
assert y.thing == "foo" // true
What are you trying to accomplish here other than that?
Edit: Try it here.
Let's say I have a DSL like this
setup {name = "aDSLScript"}
println "this is common groovy code"
doStuff {println "I'm doing dsl stuff"}
One would have a delegating class implementing the methods 'setup' and 'doStuff' usually. Beside, one could write common Groovy code to be executed (println...).
What I am searching for, is a way to execute this in two steps. In the first step only the setup method should be processed (neither println). The second step handles the other parts.
At the moment, I have two delegating classes. One implements 'setup' the other one implements 'doStuff'. But both execute the println statement, of course.
You can create a single class to intercept the method calls from the script and let it coordinate the following method invoke. I did it through reflection, but you can go declarative if you want. These are the model and script classes:
class FirstDelegate {
def setup(closure) { "firstDelegate.setup" }
}
class SecondDelegate {
def doStuff(closure) { "secondDelegate.doStuff" }
}
class MethodInterceptor {
def invokedMethods = []
def methodMissing(String method, args) {
invokedMethods << [method: method, args: args]
}
def delegate() {
def lookupCalls = { instance ->
def invokes = instance.metaClass.methods.findResults { method ->
invokedMethods.findResult { invocation ->
invocation.method == method.name ?
[method: method, invocation: invocation] : null
}
}
invokes.collect { invoked ->
invoked.method.invoke(instance, invoked.invocation.args)
}
}
return lookupCalls(new FirstDelegate()) + lookupCalls(new SecondDelegate())
}
}
Here be scripts and assertions:
import org.codehaus.groovy.control.CompilerConfiguration
def dsl = '''
setup {name = "aDSLScript"}
println "this is common groovy code"
doStuff {println "Ima doing dsl stuff"}
'''
def compiler = new CompilerConfiguration()
compiler.scriptBaseClass = DelegatingScript.class.name
def shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)
script = shell.parse dsl
interceptor = new MethodInterceptor()
script.setDelegate interceptor
script.run()
assert interceptor.invokedMethods*.method == [ 'setup', 'doStuff' ]
assert interceptor.delegate() ==
['firstDelegate.setup', 'secondDelegate.doStuff']
Notice I didn't bothered intercepting println call, which is a DefaultGroovyMethods thus, a little more cumbersome to handle.
Also having the class MethodInterceptor implementing the method delegate() is not a good idea, since this allows the user-defined script to call it.
I found a way to split up execution of the DSL script. I used a CompilationCustomizer to remove every statement from AST except the doFirst{}. So the first run will only execute doFirst. The second run does everything else. Here's some code:
class DoFirstProcessor {
def doFirst(Closure c) {
c()
}
}
class TheRestProcessor {
def doStuff(Closure c) {
c()
}
def methodMissing(String name, args) {
//nothing to do
}
}
def dsl = "
println 'this is text that will not be printed out in first line!'
doFirst { println 'First things first: e.g. setting up environment' }
doStuff { println 'doing some stuff now' }
println 'That is it!'
"
class HighlanderCustomizer extends CompilationCustomizer {
def methodName
HighlanderCustomizer(def methodName) {
super(CompilePhase.SEMANTIC_ANALYSIS)
this.methodName = methodName
}
#Override
void call(SourceUnit sourceUnit, GeneratorContext generatorContext, ClassNode classNode) throws CompilationFailedException {
def methods = classNode.getMethods()
methods.each { MethodNode m ->
m.code.each { Statement st ->
if (!(st instanceof BlockStatement)) {
return
}
def removeStmts = []
st.statements.each { Statement bst ->
if (bst instanceof ExpressionStatement) {
def ex = bst.expression
if (ex instanceof MethodCallExpression) {
if (!ex.methodAsString.equals(methodName)) {
removeStmts << bst
}
} else {
removeStmts << bst
}
} else {
removeStmts << bst
}
}
st.statements.removeAll(removeStmts)
}
}
}
}
def cc = new CompilerConfiguration()
cc.addCompilationCustomizers new HighlanderCustomizer("doFirst")
cc.scriptBaseClass = DelegatingScript.class.name
def doFirstShell = new GroovyShell(new Binding(), cc)
def doFirstScript = doFirstShell.parse dsl
doFirstScript.setDelegate new DoFirstProcessor()
doFirstScript.run()
cc.compilationCustomizers.clear()
def shell = new GroovyShell(new Binding(), cc)
def script = shell.parse dsl
script.setDelegate new TheRestProcessor()
script.run()
I did another variation of this where I execute the DSL in one step. See my blog post about it: http://hackserei.metacode.de/?p=247
I have a closure that's executed against another Groovy object as the delegate. I can do:
foo {
bar {
major = 1
}
}
but when I do:
foo {
bar {
major 1
}
}
I get an error:
> No signature of method: my.Bar.major() is applicable for argument types (java.lang.Integer) values: [1]
Possible solutions: setMajor(java.lang.Integer), getMajor(), wait(), any(), setMajor(java.lang.String), wait(long)
Bar looks something like:
class Bar {
Integer major
Integer getMajor() { return this.major }
def setMajor(Integer val) { this.major = val }
}
I thought Groovy made getters/setters transparent when dealing with property references and that referring to bar.major was the same as bar.get/setMajor(). Am I understanding this wrong, or does the meta class lookup route differ when you throw Closure delegates into the mix? The resolution strategy is DELEGATE_FIRST.
For more context: http://forums.gradle.org/gradle/topics/groovy-no-signature-of-method-running-closure-against-delegate
you would have to add also void major(Integer val). major = 1 is groovy-short for setMajor(1) while major 1 is short for major(1). (see Section Optional parenthesis)
Optional parenthesis
Method calls in Groovy can omit the parenthesis if there is at least one parameter and there is no ambiguity.
println "Hello world"
System.out.println "Nice cheese Gromit!"
E.g.:
class X {
Integer major
void major(Integer m) { major = m }
}
def x = new X()
x.major = 1 // x.setMajor(1)
assert x.major==1 // x.getMajor()==1
x.major 2 // x.major(2)
assert x.major==2
If you need this behaviour alot, you can add a methodMissing for this case. E.g.:
class X {
Integer major
def methodMissing(String name, args) {
if (this.hasProperty(name) && args.size()==1) {
this."$name" = args[0]
} else {
throw new MissingMethodException(name, this.class, args)
}
}
}
def x = new X()
x.major = 1
assert x.major==1
x.major 2
assert x.major==2
How can I deep copy a map of maps in Groovy? The map keys are Strings or Ints. The values are Strings, Primitive Objects or other maps, in a recursive way.
An easy way is this:
// standard deep copy implementation
def deepcopy(orig) {
bos = new ByteArrayOutputStream()
oos = new ObjectOutputStream(bos)
oos.writeObject(orig); oos.flush()
bin = new ByteArrayInputStream(bos.toByteArray())
ois = new ObjectInputStream(bin)
return ois.readObject()
}
To go about deep copying each member in a class, the newInstance() exists for Class objects. For example,
foo = ["foo": 1, "bar": 2]
bar = foo.getClass().newInstance(foo)
foo["foo"] = 3
assert(bar["foo"] == 1)
assert(foo["foo"] == 3)
See http://groovy-lang.org/gdk.html and navigate to java.lang, Class, and finally the newInstance method overloads.
UPDATE:
The example I have above is ultimately an example of a shallow copy, but what I really meant was that in general, you almost always have to define your own reliable deep copy logic, with perhaps using the newInstance() method, if the clone() method is not enough. Here's several ways how to go about that:
import groovy.transform.Canonical
import groovy.transform.AutoClone
import static groovy.transform.AutoCloneStyle.*
// in #AutoClone, generally the semantics are
// 1. clone() is called if property implements Cloneable else,
// 2. initialize property with assignment, IOW copy by reference
//
// #AutoClone default is to call super.clone() then clone() on each property.
//
// #AutoClone(style=COPY_CONSTRUCTOR) which will call the copy ctor in a
// clone() method. Use if you have final members.
//
// #AutoClone(style=SIMPLE) will call no arg ctor then set the properties
//
// #AutoClone(style=SERIALIZATION) class must implement Serializable or
// Externalizable. Fields cannot be final. Immutable classes are cloned.
// Generally slower.
//
// if you need reliable deep copying, define your own clone() method
def assert_diffs(a, b) {
assert a == b // equal objects
assert ! a.is(b) // not the same reference/identity
assert ! a.s.is(b.s) // String deep copy
assert ! a.i.is(b.i) // Integer deep copy
assert ! a.l.is(b.l) // non-identical list member
assert ! a.l[0].is(b.l[0]) // list element deep copy
assert ! a.m.is(b.m) // non-identical map member
assert ! a.m['mu'].is(b.m['mu']) // map element deep copy
}
// deep copy using serialization with #AutoClone
#Canonical
#AutoClone(style=SERIALIZATION)
class Bar implements Serializable {
String s
Integer i
def l = []
def m = [:]
// if you need special serialization/deserialization logic override
// writeObject() and/or readObject() in class implementing Serializable:
//
// private void writeObject(ObjectOutputStream oos) throws IOException {
// oos.writeObject(s)
// oos.writeObject(i)
// oos.writeObject(l)
// oos.writeObject(m)
// }
//
// private void readObject(ObjectInputStream ois)
// throws IOException, ClassNotFoundException {
// s = ois.readObject()
// i = ois.readObject()
// l = ois.readObject()
// m = ois.readObject()
// }
}
// deep copy by using default #AutoClone semantics and overriding
// clone() method
#Canonical
#AutoClone
class Baz {
String s
Integer i
def l = []
def m = [:]
def clone() {
def cp = super.clone()
cp.s = s.class.newInstance(s)
cp.i = i.class.newInstance(i)
cp.l = cp.l.collect { it.getClass().newInstance(it) }
cp.m = cp.m.collectEntries { k, v ->
[k.getClass().newInstance(k), v.getClass().newInstance(v)]
}
cp
}
}
// assert differences
def a = new Bar("foo", 10, ['bar', 'baz'], [mu: 1, qux: 2])
def b = a.clone()
assert_diffs(a, b)
a = new Baz("foo", 10, ['bar', 'baz'], [mu: 1, qux: 2])
b = a.clone()
assert_diffs(a, b)
I used #Canonical for the equals() method and tuple ctor. See groovy doc Chapter 3.4.2, Code Generation Transformations.
Another way to go about deep copying is using mixins. Let's say you wanted an existing class to have deep copy functionality:
class LinkedHashMapDeepCopy {
def deep_copy() {
collectEntries { k, v ->
[k.getClass().newInstance(k), v.getClass().newInstance(v)]
}
}
}
class ArrayListDeepCopy {
def deep_copy() {
collect { it.getClass().newInstance(it) }
}
}
LinkedHashMap.mixin(LinkedHashMapDeepCopy)
ArrayList.mixin(ArrayListDeepCopy)
def foo = [foo: 1, bar: 2]
def bar = foo.deep_copy()
assert foo == bar
assert ! foo.is(bar)
assert ! foo['foo'].is(bar['foo'])
foo = ['foo', 'bar']
bar = foo.deep_copy()
assert foo == bar
assert ! foo.is(bar)
assert ! foo[0].is(bar[0])
Or categories (again see the groovy doc) if you wanted deep copying semantics based on some sort of runtime context:
import groovy.lang.Category
#Category(ArrayList)
class ArrayListDeepCopy {
def clone() {
collect { it.getClass().newInstance(it) }
}
}
use(ArrayListDeepCopy) {
def foo = ['foo', 'bar']
def bar = foo.clone()
assert foo == bar
assert ! foo.is(bar)
assert ! foo[0].is(bar[0]) // deep copying semantics
}
def foo = ['foo', 'bar']
def bar = foo.clone()
assert foo == bar
assert ! foo.is(bar)
assert foo[0].is(bar[0]) // back to shallow clone
For Json (LazyMap) this wokred for me
copyOfMap = new HashMap<>()
originalMap.each { k, v -> copyOfMap.put(k, v) }
copyOfMap = new JsonSlurper().parseText(JsonOutput.toJson(copyOfMap))
EDIT: Simplification by: Ed Randall
copyOfMap = new JsonSlurper().parseText(JsonOutput.toJson(originalMap))
I've just hit this issue as well, and I just found:
deepCopy = evaluate(original.inspect())
Although I've been coding in Groovy for less than 12 hours, I wonder if there might be some trust issues with using evaluate. Also, the above doesn't handle backslashes. This:
deepCopy = evaluate(original.inspect().replace('\\','\\\\'))
does.
I am afraid you have to do it the clone way. You could give Apache Commons Lang SerializationUtils a try
Is it possible to get a reference of the Object that invoked a Closure in the Closure's execution context?
For example:
public class Example {
public Example(){
def a = {return this};
def b = [];
b.metaClass.a = a;
println b.a();
}
}
I want this execution to return b instead of an instance of Example.
The object that the closure is invoked on can be referenced as delegate. Example:
def a = { return delegate }
def b = []
b.metaClass.a = a
assert b.a() == b