Groovy Closure reuse vs rehydrate copy - groovy

In the DSL page of groovy they show this
def email(Closure cl) {
def email = new EmailSpec()
def code = cl.rehydrate(email, this, this)
code.resolveStrategy = Closure.DELEGATE_ONLY
code()
}
Why are they calling rehydrate instead of just assigning the delegate to the closure:
def email(Closure cl) {
def email = new EmailSpec()
cl.delegate = email
cl.resolveStrategy = Closure.DELEGATE_ONLY
cl()
}
In other words, why do we need a copy of the closure instead of reusing the one given. I don't necessarily see a problem with using rehydrate but I also don't see the need, which tells me there's something I'm not understanding

I imagine it returns a copy rather than reusing the same closure in order to stay idempotent/safe in case you still need a reference to the old closure.
As #tim_yates mentioned, the rehydrate method sets the delegate, owner, and thisObject, whereas your second example only sets the delegate. It's not that the rehydrate method does anything magical, it's just a convenience method so you don't have to set all three properties individually/line-by-line.
I also believe rehydrate is meant to work with its partner method dehydrate, which returns a copy of the closure with those three fields cleared (allowing rehydrate to easily re-set them).

Related

Is it possible to get the name of variable in Groovy?

I would like to know if it is possible to retrieve the name of a variable.
For example if I have a method:
def printSomething(def something){
//instead of having the literal String something, I want to be able to use the name of the variable that was passed
println('something is: ' + something)
}
If I call this method as follows:
def ordinary = 58
printSomething(ordinary)
I want to get:
ordinary is 58
On the other hand if I call this method like this:
def extraOrdinary = 67
printSomething(extraOrdinary)
I want to get:
extraOrdinary is 67
Edit
I need the variable name because I have this snippet of code which runs before each TestSuite in Katalon Studio, basically it gives you the flexibility of passing GlobalVariables using a katalon.features file. The idea is from: kazurayam/KatalonPropertiesDemo
#BeforeTestSuite
def sampleBeforeTestSuite(TestSuiteContext testSuiteContext) {
KatalonProperties props = new KatalonProperties()
// get appropriate value for GlobalVariable.hostname loaded from katalon.properties files
WebUI.comment(">>> GlobalVariable.G_Url default value: \'${GlobalVariable.G_Url}\'");
//gets the internal value of GlobalVariable.G_Url, if it's empty then use the one from katalon.features file
String preferedHostname = props.getProperty('GlobalVariable.G_Url')
if (preferedHostname != null) {
GlobalVariable.G_Url = preferedHostname;
WebUI.comment(">>> GlobalVariable.G_Url new value: \'${preferedHostname}\'");
} else {
WebUI.comment(">>> GlobalVariable.G_Url stays unchanged");
}
//doing the same for other variables is a lot of duplicate code
}
Now this only handles 1 variable value, if I do this for say 20 variables, that is a lot of duplicate code, so I wanted to create a helper function:
def setProperty(KatalonProperties props, GlobalVariable var){
WebUI.comment(">>> " + var.getName()" + default value: \'${var}\'");
//gets the internal value of var, if it's null then use the one from katalon.features file
GlobalVariable preferedVar = props.getProperty(var.getName())
if (preferedVar != null) {
var = preferedVar;
WebUI.comment(">>> " + var.getName() + " new value: \'${preferedVar}\'");
} else {
WebUI.comment(">>> " + var.getName() + " stays unchanged");
}
}
Here I just put var.getName() to explain what I am looking for, that is just a method I assume.
Yes, this is possible with ASTTransformations or with Macros (Groovy 2.5+).
I currently don't have a proper dev environment, but here are some pointers:
Not that both options are not trivial, are not what I would recommend a Groovy novice and you'll have to do some research. If I remember correctly either option requires a separate build/project from your calling code to work reliable. Also either of them might give you obscure and hard to debug compile time errors, for example when your code expects a variable as parameter but a literal or a method call is passed. So: there be dragons. That being said: I have worked a lot with these things and they can be really fun ;)
Groovy Documentation for Macros
If you are on Groovy 2.5+ you can use Macros. For your use-case take a look at the #Macro methods section. Your Method will have two parameters: MacroContext macroContext, MethodCallExpression callExpression the latter being the interesting one. The MethodCallExpression has the getArguments()-Methods, which allows you to access the Abstract Syntax Tree Nodes that where passed to the method as parameter. In your case that should be a VariableExpression which has the getName() method to give you the name that you're looking for.
Developing AST transformations
This is the more complicated version. You'll still get to the same VariableExpression as with the Macro-Method, but it'll be tedious to get there as you'll have to identify the correct MethodCallExpression yourself. You start from a ClassNode and work your way to the VariableExpression yourself. I would recommend to use a local transformation and create an Annotation. But identifying the correct MethodCallExpression is not trivial.
no. it's not possible.
however think about using map as a parameter and passing name and value of the property:
def printSomething(Map m){
println m
}
printSomething(ordinary:58)
printSomething(extraOrdinary:67)
printSomething(ordinary:11,extraOrdinary:22)
this will output
[ordinary:58]
[extraOrdinary:67]
[ordinary:11, extraOrdinary:22]

Accessing a variable defined in another function in Groovy

I am new to Groovy.
I have a function in which I am writing a value to map.
def addTraceEntry(key, value) {
def traceability = [:]
traceability[key] = value.trim()
println "This print happens in function addTraceEntry " + traceability
}
I have another function that needs to verify whether the above function works properly.
def testAddTraceEntry() {
def key = 'test_key'
def value = 'test_value'
addTraceEntry(key, value)
println "This print happens in function testAddTraceEntry " + traceability
assert value == traceability[key]
}
I am invoking the testAddTraceEntry() function using the function name:
testAddTraceEntry()
When I run this, I get the ERROR:
This print happens in function addTraceEntry [test_key:test_value]
Caught: groovy.lang.MissingPropertyException: No such property: traceability for class: HelloWorld
groovy.lang.MissingPropertyException: No such property: traceability for class: HelloWorld
at HelloWorld.testAddTraceEntry(HelloWorld.groovy:53)
at HelloWorld.run(HelloWorld.groovy:57)
In the function testAddTraceEntry it clearly does not know the value of traceability so seems like its giving an ERROR for that.
I tried to return the value of traceability.
def addTraceEntry(key, value) {
def traceability = [:]
traceability[key] = value.trim()
println "This print happens in function addTraceEntry " + traceability
return traceability
}
But this yields the same ERROR.
There are a bunch of things worth mentioning after seeing the code you have wrote.
First thing - the scope of variables and encapsulation. Let's throw away technicalities for a moment and focus on something even more important. In method addTraceEntry you persist some state, which is fine. However, the implementation of the method testAddTraceEntry reveals that this method tries to know way to much about the implementation details of addTraceEntry. It encapsulates (hides in other words) persistence logic (from the API point of view you, as a caller, don't know that it persists key and a value inside the map) and that is why testAddTraceEntry should never ever make assumptions that calling this method mutated some structure. If you do so, then:
your test method contracts side effects and not the expected business logic (storing data in some kind of global map - don't do it. Ever)
your test blocks any evolution of tested method implementation - imagine, that you decided to store key and value in a different structure. You may do it without breaking any API contract (your function produces the same results), but the test method will fail and you will have to modify it.
Second thing - your addTraceEntry method always produces a map with a single entry. It doesn't make much sense and if you call your function let's say 4 times you will end up with 4 maps where each one of them contain a single key mapped to a single value.
There are at least various ways to improve implementation of your methods. The simplest thing you can do is to implement a class that encapsulates logic for storing keys and values. Consider following example:
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
class TraceEntriesStorage {
private final ConcurrentMap<String, Object> entries = [:] as ConcurrentHashMap
def addTraceEntry(String key, Object value) {
entries.put(key, value)
}
def containsTraceEntry(String key) {
return entries.containsKey(key)
}
def retrieveTraceEntryForKey(String key) {
return entries.get(key)
}
}
This is a simple class with 3 short methods. It stores trace entries inside the internal concurrent map (to solve problems with concurrent access). Now, your test method could look like this:
def storage = new TraceEntriesStorage()
storage.addTraceEntry("test_key", "test_value")
assert storage.containsTraceEntry("test_key")
assert storage.retrieveTraceEntryForKey("test_key") == "test_value"
You create an instance of this class, you add an entry and you check if methods containsTraceEntry and retrieveTraceEntryForKey return expected values. As you can see it doesn't matter where we stored this trace entry - it matters that the class we have implemented behaves as expected. To make this test method even better you could add an assertion that checks if there is no trace entry for test_key before we actually insert it - this way we know that adding trace entry change internal state of the class. But what is nice in this approach is that as long as we don't break the contract, we can experiment and modify implementation of TraceEntriesStorage. Because what is most important - adding trace entries have to allow to retrieve them back from the object. How it gets stored, where it gets stored - it doesn't matter.
I hope you find this answer useful and it will help you in learning Groovy and designing a better programs. Happy hacking!
You need to combine adding the return statement to addTraceEntry() with assigning the returned value to a variable in testAddTraceEntry():
def traceability = addTraceEntry(key, value)

Nomin automap causes infinite loop

I am using Nomin for mapping tasks. As taken from the documentation of Nomin it should be able to map fields with the same name by itself in case automapping has been activated. When activating it, it causes an infinite loop exception.
I have the following:
mappingFor a: CoinsOnMarketPlace, b: Coin
// automap() // when deactivated it works fine, when activated infinite loop
a.coin.name = b.name
a.coin.rank = b.rank
a.priceUSD = b.priceUSD // Could be automapped
a.priceBTC = b.priceBTC // Could be automapped
...
Exception:
org.nomin.core.NominException: ./net/hemisoft/ccm/repository/coinmarketcap2coin.groovy: Recursive mapping rule a = b causes infinite loop!
One thing worth adding regarding your use case - this Recursive mapping rule a = b causes infinite loop! exception is thrown because you use groovy classes in your mapping rule. Nomin uses ReflectionIntrospector and what's important:
It performs getting/setting properties using accessor methods which are called through the Java reflection mechanism. ReflectionIntrospector uses supplied NamingPolicy instance to determine accessor methods. JbNamingPolicy is used by default, this implementation cerresponds the JavaBeans convention. Its InstanceCreator named ReflectionInstanceCreator instantiates objects using Class.newInstance().
Source: http://nomin.sourceforge.net/introspectors.html
A simple Groovy class like:
class Entity {
String name
String somethingElse
}
gets compiled to a Java class that implements GroovyObject providing following methods:
public interface GroovyObject {
Object invokeMethod(String var1, Object var2);
Object getProperty(String var1);
void setProperty(String var1, Object var2);
MetaClass getMetaClass();
void setMetaClass(MetaClass var1);
}
In this case ReflectionInstanceCreator combined with automap() resolves following mappings:
a.property = b.property
and
a = b
where a = b mapping comes from MetaClass getMetaClass() getter method I suppose, because there is no mapping like a.metaClass = b.metaClass resolved. a.property = b.property gets resolved because of Object getProperty(String var1) method.
Solution
This problem can be solved by specifying explicitly ExplodingIntrospector for your mapping script that:
It performs getting/setting properties using a class field immediately through through the Java reflection mechanism and may be useful in case when domain object don't provide accessors for their properties. Supplied instance creator is ReflectionInstanceCreator.
Source: http://nomin.sourceforge.net/introspectors.html
All you have to do is to add
introspector exploding
right below mappingFor a: ..., b: ... header. For example:
import mypackage.Entity
import mypackage.EntityDto
mappingFor a: Entity, b: EntityDto
introspector exploding
automap()
a.test2 = b.test1
Tested with two Groovy classes, worked like a charm. Hope it helps.

For Geb Page Object, when is the static content block initialized?

When following the geb page object pattern, it is encouraged to create a static block of values that represent the elements on the page you are attempting to interface with. It is also good to create an at checker. Here is an example:
class SomePage extends Page{
static at = {$(By.xpath("some header or something")).displayed}
static content = {
element1 {$(By.xpath("some xpath1"))}
element2 {$(By.xpath("some xpath2"))}
//so on and so forth
}
}
Now I think I know the answer this question already but could not find the docs to back it up. I am pretty sure that the static content block is initialized once the "at checker" is called from a test script, but I am not sure. If what I am suggesting is true then that would mean something like this:
class SomePage extends Page{
static at = {$(By.xpath("some header or something")).displayed}
def someString
static content = {
element1 {$(By.xpath("//*[contains(text(), ${someString}"))}
element2 {$(By.xpath("some xpath2"))}
//so on and so forth
}
def setSomeString(String x){
this.someString = x
}
}
would be impractical right, or maybe even impossible? This is because in order to call "setSomeString" you need to call the at checker to tell the script which class to reference for method and variable calls, but if you call the at checker that means the static content becomes initialized.
Furthermore, if a webpage has content that doesn't show up upon initial arrival to the webpage, then you would not be able to put that content into the static content block either, since the at checker should be called as soon as you arrive on said webPage.
I am simply looking to confirm or deny that this is the behavior of geb page object. and I would be happy to hear answers describing best practice given the above situation.
also if there is a way to re-initialize the content, I would like to know that too, but I figure there is not.
A content definition is evaluated every time the result of the definition is requested:
def somePage = to SomePage //at checker is executed but the defintion for element1 isn't
somePage.element1 // closure defined for element1 is executed
somePage.element1 // and here again
// many lines of code which trigger additional content to show up on the page
somePage.element1 // closure defined for element1 is executed again

Getting Key reference from KeyValuePair

I have the following class.
public class myType
{
public event Action myAction;
}
And a Dictionary containing some instances of that class.
var myDictionary = new Dictionary<myType, string>();
In my Main I have a method with signature
void SomeMethod(myType, Dictionary)
With the following loop I add my object's behaviour:
foreach(var pair in myDictionary)
pair.Key.myAction += () => SomeMethod(pair.Key, myDictionary);
After running this loop, when the action of one of my objects is invoked, the effect is as if the loop had used the last pair.Key in the dictionary for all the lambda expressions.
On the other hand with a small change in the loop:
foreach(var pair in myDictionary)
{
myType temp = pair.Key;
pair.Key.myAction += () => SomeMethod(temp, myDictionary);
}
After running this loop, all the object actions work as expected.
I'm a bit at a loss why such a change would have such an effect. A keyvaluepair may be a struct, by the key itself is a reference type (an instance of my class). Any ideas why this behaves this way?
Thanks in advance for any suggestions.
After running this loop, when the action of one of my objects is
invoked, the effect is as if the loop had used the last pair.Key in
the dictionary for all the lambda expressions.
Yes, that's exactly what's happening. You have a single variable pair that is used by all the event handlers. After the loop the variable contains the key of the last item in the loop.
By creating a local variable in the scope and using that in the lambda expression, you are actually creating a closure for each event handler. The local variable is not stored on the stack as a regular local varible, but in the closure, and as each event handler has its own closure, you get one version of the local variable for each event handler.
(There is a closure with the first code also, but that is just for the variable to survive the current scope, the event handlers share the same closure.)

Resources