How can I get the value of a variable named after another one in groovy? - variables

I have a variable that contains the name of another variable which I want to retrieve the value, e.g.:
def variable = "finalVariableValue"
def variableName = "variable"
How can I get variable.value as I only know variableName?
I've seen the a Binding could be used but I have a lot of variable that I need to put on this Binding object in order to make it works. Is the only way?
NB: this behaviour is really similar to the ant property extension mechanism.
Thanks,
Michele.

By prefixing it with def you are not registering it in an object you can inspect, like a map; one could argue it is registered in the AST, but that is a rocky road.
My 0.03 are working with a map, with a binding, or with dynamic properties. Drop the def part and choose one of the solutions:
Map
Simply declare the variable as a key in a map:
def map = [:]
map.variable = "finalVariableValue"
def variableName = "variable"
assert map[variableName] == "finalVariableValue"
Binding (with script)
Use the script built-in binding. Note this only works with scripts:
variable = "finalVariableValue"
variableName = "variable"
assert binding[variableName] == "finalVariableValue"
Dynamic properties
Use some dynamic properties mechanism, like an Expando (also, you could use getProperty with setProperty and others):
class Container extends Expando {
def declare() {
variable = "finalVariableValue"
variableName = "variable"
}
}
c = new Container()
c.declare()
assert c[c.variableName] == "finalVariableValue"

You can use the script's scope, simply dropping the Type definition:
variable = 'value'
name = 'variable'
assert 'variable' == this.name
assert 'value' == this[this.name]
or using #Field annotation:
import groovy.transform.Field
#Field def variable = 'value'
#Field def name = 'variable'
assert 'variable' == this.name
assert 'value' == this[this.name]

Related

Groovy : Class.forName().newInstance() error

I have this following method in which I return a List<ImField> object using the List<GPathResult> filteredList. I perform filteredList.each closure where I generate
class at runtime and assign it a static type of ImField.
static List<ImField> getFields(GPathResult root,String fieldClass, String fieldType){
List<GPathResult> filteredList = root.children().findAll{
XMLSlurperUtil.name(it as GPathResult) == fieldType
} as List<GPathResult>
List<ImField> fields = []
filteredList.each{GPathResult it, int index ->
fields.add(Class.forName(fieldClass).newInstance() as ImField)
fields[index].set(it)
}
fields
}
The function call would look like so :
ImStageUtil.getFields(root, ImFieldFactory.SOURCE_FIELD, ImParserConstants.SOURCE_FIELD)
where ImFieldFactory.SOURCE_FIELD = "com.dto.fields.SourceField"
and ImParserContants.SOURCE_FIELD = "SOURCEFIELD"
the error occurs at the .each closure line:
No signature of method: com.extractor.ImStageUtil$_getFields_closure11.doCall() is applicable for argument types: (groovy.util.slurpersupport.NodeChild) values: []
Possible solutions: doCall(groovy.util.slurpersupport.GPathResult, int), findAll(), findAll(), isCase(java.lang.Object), isCase(java.lang.Object)
groovy.lang.MissingMethodException: No signature of method: com.extractor.ImStageUtil$_getFields_closure11.doCall() is applicable for argument types: (groovy.util.slurpersupport.NodeChild) values: []
Possible solutions: doCall(groovy.util.slurpersupport.GPathResult, int), findAll(), findAll(), isCase(java.lang.Object), isCase(java.lang.Object)
I've tried to create a similar script to your example, there are two things I had to modify (if your filteredList is not empty, which you need to check first):
1- You need to use collect() after the findAll{} closure, this allows you to collect all entries and add them to your filteredList.
2- You're using .each{} and you're providing a List along with the index, this should be replaced by .eachWithIndex{} because the first one doesn't expect an index.
Here is a simplified version of your code:
import groovy.util.slurpersupport.GPathResult
def text = '''
<list>
<technology>
<name>Groovy</name>
</technology>
</list>
'''
def list = new XmlSlurper().parseText(text)
def List getFields(GPathResult root,String fieldClass, String fieldType){
List<GPathResult> filteredList = root.children().findAll{
//println(it)
it != null
}.collect() as List<GPathResult>
println('list: ' + filteredList.getClass() + ', ' + filteredList.size())
filteredList.eachWithIndex{GPathResult it, int index ->
println('it: ' + it)
}
}
getFields(list, '', '')
This last example doesn't raise any exception for me.
Hope this helps.

Terraform: Set optional resource attribute if condition is met, otherwise don't declare it

Some resources on Terraform support optional attributes. I'm interested in declaring and setting a value for the optional attribute only if a condition is met. Otherwise, don't declare it at all.
All of the suggestions I found was based on declaring the attribute and setting its value to null if the condition isn't satisfied, instead of not declaring the attribute at all.
Is there a way for me to do something like the following? In pseudo-code:
resource "some_resource" "this" {
name = var.name
if var.name == "some_name":
some_optional_attribute = "some_value"
else:
pass # do nothing, don't even declare the optional attribute
}
Let me know, thanks in advance!
I don't believe there is a better method than simply doing the following:
resource "some_resource" "this" {
some_optional_attribute = var.name == "some_name" ? var.name : null
}
When you declare attribute as null that basically means that it is not being used. The above in my opinion is equivalent to your if statement.

warning variable unused in assert

I can test the content after a redirection like this
assert "/url" = redir_path = redirected_to(conn, 302)
conn = get(recycle(conn), redir_path)
assert html_response(conn, 200) == "Content after redirection"
But I cannot add a param variable to the assert url like this:
id = 10
assert "/url/#{id}" = redir_path = redirected_to(conn, 302)
It complains with:
cannot invoke remote function id/0 inside match
So if I just define the path like this before using it:
url_path = "/url/%{id}"
assert url_path = redir_path = redirected_to(conn, 302)
warning: variable "url_path" is unused
?? unusued? is it being used inside the assert...
Not sure how to silence that warning or how to approach this.
The code is similar to Chris's response here:
https://elixirforum.com/t/following-redirection-in-controllertests/10084
warning: variable "url_path" is unused
?? unusued? is it being used inside the assert...
No, it's not. Your assert will match any value because if you have a variable name on the LHS of a match, it matches any value and that variable gets assigned the value of the RHS.
In:
foo = 10
assert foo = 20
IO.inspect foo
the assert passes and foo is printed as 20.
If you just want to assert that that string equals the value returned by redirected_to/2, you can use ==:
assert "/url/#{id}" == redirected_to(conn, 302)

What does [:] mean in groovy?

While reading some groovy code of another developer I encountered the following definition:
def foo=[:]
What does it mean?
[:] is shorthand notation for creating a Map.
You can also add keys and values to it:
def foo = [bar: 'baz']
[:] creates an empty Map. The colon is there to distinguish it from [], which creates an empty List.
This groovy code:
def foo = [:]
is roughly equivalent to this java code:
Object foo = new java.util.LinkedHashMap();
Quoting the doc:
Notice that [:] is the empty map expression.
... which is the only Map with size() returning 0. ) By itself, it's rarely useful, but you can add values into this Map, of course:
def emptyMap = [:]
assert emptyMap.size() == 0
emptyMap.foo = 5
assert emptyMap.size() == 1
assert emptyMap.foo == 5

JSON Grail Groovy Update SQL

Using a Groovy script with grails and want to do an update to a record in the database. I do the basic get the object from JSON and convert it to the Domain class and then do save() on it. From what I understand since I am new to Groovy and grails the save should update if the "id" is already there. But I don't get that, I get the standard SQL error of "Duplicate entry '1' for key 'PRIMARY'". How do I fix this?
def input = request.JSON
def instance = new Recorders(input)
instance.id = input.getAt("id")
instance.save()
and my domain is:
class Recorders {
Integer sdMode
Integer gsmMode
static mapping = {
id generator: "assigned"
}
static constraints = {
sdMode nullable: true
gsmMode nullable: true
}
}
Instead of doing a new Recorders(input), you probably ought to get it:
def input = request.JSON
def instance = Recorders.get(input.getAt('id'))
instance.properties = input
instance.save()
Edit
(From your comment) If it doesn't exist and you want to insert it:
def input = request.JSON
def id = input.getAt('id')
def instance = Recorders.get(id)
if(!instance) {
instance = new Recorders(id: id)
}
instance.properties = input
instance.save()
I don't use assigned id generators much, so I'm not sure if Grails will bind the id automatically (since it's expecting it to be assigned). If it does, you can probably remove the id: id from the Recorders() constructor.