I am trying to replicate the Verbal Expression library for python in Genie as an exercise to learn how to use classes. I've got simple classes like the ones listed at the tutorial down, however when it comes to instatiate methods in a object oriented fashion I am running into problems. Here is what I am trying:
For training purposes I want a method called add that behaves identically as string.concat().
[indent=4]
class VerEx : Object
def add(strg:string) : string
return this.concat(strg)
But I get the error:
verbalexpressions.gs:33.16-33.26: error: The name `concat' does not exist in the context of `VerEx'
When I use a different approach, like:
class VerEx : Object
def add(strg:string) : string
a:string=""
a.concat(strg)
return a
init
test:string = "test"
sec:string = " + a bit more"
print test.VerEx.add(sec)
I get the error in the last line of the above text, with the warning:
verbalexpressions.gs:84.11-84.21: error: The name `VerEx' does not exist in the context of `string?'
I want to be able to make test.add(sec) behave identically to test.concat(sec), what can I do to achieve this?
a small example for this,
Note:
unhandle RegexError in
new Regex
r.replace
[indent=4]
class VerX
s: GenericArray of string
construct ()
s = new GenericArray of string
def add (v: string): VerX
s.add (v)
return self
def find (v: string): VerX
return self.add ("(%s)".printf (v))
def replace(old: string, repl: string): string
// new Regex: unhandle RegexError HERE!!
var r = new Regex (#"$(self)")
// r.replace: unhandle RegexError HERE!!
return r.replace(old, old.length, 0, repl)
def to_string (): string
return string.joinv ("", s.data)
init
var replace_me = "Replace bird with a duck"
var v = new VerX
print v.find("bird").replace(replace_me, "duck")
var result = (new VerX).find("red").replace("We have a red house", "blue")
print result
Related
I have a similar question to this:
Groovy string interpolation with value only known at runtime
What can be done to make the following work:
def message = 'Today is ${date}, your id is: ${id}';
def date1 = '03/29/2019'
def id1 = '12345'
def result = {date, id -> "${message}"}
println(result(date1, id1))
So I want to take a string that has already been defined elsewhere (for simplicity I define it here as 'message'), having the interpolated ${date} and ${id} already embedded in it, and process it here using the closure, with definitions for the input fields.
I've tried this with various changes, defining message in the closure without the "${}", using single or double quotes, embedding double quotes around the interpolated vars in the string 'message', etc., I always get this result:
Today is ${date}, your id is: ${id}
But I want it to say:
Today is 03/29/2019, your id is: 12345
The following worked but I am not sure if it is the best way:
def message = '"Today is ${date}, your id is: ${id}"'
def sharedData = new Binding()
def shell = new GroovyShell(sharedData)
sharedData.setProperty('date', '03/29/2019')
sharedData.setProperty('id', '12345')
println(shell.evaluate(message))
http://docs.groovy-lang.org/latest/html/documentation/guide-integrating.html
ernest_k is right, you can use the templating engine for exactly this:
import groovy.text.SimpleTemplateEngine
def templatedMessage = new SimpleTemplateEngine().createTemplate('Today is ${date}, your id is: ${id}')
def date1 = '03/29/2019'
def id1 = '12345'
def result = { date, id -> templatedMessage.make(date: date, id: id)}
println(result(date1, id1))
I want to use for scripting external Groovy Scripts.
To not copy a lot of code, I want to share classes.
I have:
- external_test.groovy
- Input.groovy
Running the external_test.groovy in Intellij works.
Input is a simple class:
package helpers
class Input {
String serviceConfig
String httpMethod
String path
LinkedHashMap headers = [:]
String payload
Boolean hasResponseJson
}
When the script is executed by Camunda, it cannot find the class:
import helpers.Input
...
And throws an Exception:
unable to resolve class helpers.Input # line 16, column 9. new helpers.Input(serviceConfig: "camundaService", ^ 1 error
It is listed in the Deployment:
Do I miss something or is this not supported?
I found a post in the Camunda forum, that helped me to solve this:
https://forum.camunda.org/t/groovy-files-cant-invoke-methods-in-other-groovy-files-which-are-part-of-same-deployment/7750/5
Here is the solution (that is not really satisfying - as it needs a lot of boilerplate code):
static def getScript(fileName, execution) {
def processDefinitionId = execution.getProcessDefinitionId()
def deploymentId = execution.getProcessEngineServices().getRepositoryService().getProcessDefinition(processDefinitionId).getDeploymentId()
def resource = execution.getProcessEngineServices().getRepositoryService().getResourceAsStream(deploymentId, fileName)
def scannerResource = new Scanner(resource, 'UTF-8')
def resourceAsString = scannerResource.useDelimiter('\\Z').next()
scannerResource.close()
GroovyShell shell = new GroovyShell()
return shell.parse(resourceAsString)
}
def helper = getScript("helpers/helper_classes.groovy", execution)
helper.myFunction("hello")
I am trying to write a method that:
Loads a template file (*.tpl) from the local file system
Parameterizes that template file with a list of supplied variables
Best attempt thus far:
String loadParameterizedTemplateByName(String templateName,
String... variables) {
InputStream inputStream =
this.class.classLoader.getResourceAsStream(templateName)
StringWriter writer = new StringWriter()
IOUtils.copy(inputStream, writer, 'UTF-8')
String templateBody = writer.toString()
def binding = variablesAsBinding(variables) // ?!?!
engine.createTemplate(templateBody).make(binding).toString()
}
So for instance say I have the following HelloEmail.tpl template file:
HelloEmail.tpl
==============
Hello ${firstName},
You are awesome! ${someGuy} even says so!
Sincerely,
${me}
Then my desired invocation of this would be:
String firstName = 'John'
String someGuy = 'Mark'
String me = '#smeeb'
String parameterizedTemplate =
loadParameterizedTemplateByName('HelloEmail.tpl', firstName, someGuy, me)
So that the final result is that parameterizedTemplate string has a value of:
println parameterizedTemplate
// Prints:
Hello John,
You are awesome! Mark even says so!
Sincerely,
#smeeb
The trick here is that the method needs to be able to use any list of supplied variables against any supplied template file!
Is this possible to accomplish via reflection? Meaning the TemplateEngine just looks as the supplied list of String variables, and substitutes them for variables of the same name (as found in the template)?
You can pass a Map like so:
import groovy.text.markup.MarkupTemplateEngine
import groovy.text.markup.TemplateConfiguration
String loadParameterizedTemplateByName(Map variables, String templateName) {
def engine = new groovy.text.SimpleTemplateEngine()
this.class.getResource(templateName).withReader { reader ->
engine.createTemplate(reader).make(variables)
}
}
def result = loadParameterizedTemplateByName('/mail.tpl', firstName:'Tim', someGuy:'StackOverflow', me:'smeeb')
assert result == 'Hello Tim,\n\nYou are awesome! StackOverflow even says so!\n\nSincerely,\nsmeeb'
Another question answers how to define a one-to-many association, by defining a method in the "one" case class (Directorate) that returns a Seq of the "many" class (ServiceArea).
But it doesn't address the "bidirectional" part of the question.
Using that example, I'd like to see how to traverse the association from the other direction.
Instead of
case class ServiceArea(areaCode: String, dirCode: String, name: String)
I'd like to see
case class ServiceArea(areaCode: String, directorate: Directorate, name: String)
Is this possible with Slick?
Because when I try something like
object ServiceAreas ...
def * = areaCode ~ directorate ~ name <> (ServiceArea, ServiceArea.unapply _)
it fails to compile, not finding an implicit value for evidence parameter of type TypeMapper[ForeignKeyQuery[ServiceAreas,ServiceArea]].
You have to adjust your way of thinking a little. Slick handles composition and execution of queries, but as you mentioned in your comment, it's not an ORM (thank goodness).
Have a look at the code you referenced:
case class ServiceArea(areaCode: String, dirCode: String, name: String)
object ServiceAreas extends Table[ServiceArea]("SERVICE_AREAS") {
def areaCode = column[String]("AREAE_CODE", O.PrimaryKey)
def dirCode = column[String]("DIRECTORATE_CODE")
def name = column[String]("NAME")
def directorate = foreignKey("DIR_FK", dirCode, Directorates)(_.dirCode)
def * = areaCode ~ dirCode ~ name <> (ServiceArea, ServiceArea.unapply _)
}
The link to directorate is already defined by a navigatable foreign key.
So now you can write a query like this:
def directorates = for {
area <- Parameters[String]
sa <- ServiceAreas if sa.areaCode === area
dir <- sa.directorate
} yield dir
Which will yield a Directorate for each match.
I am wondering if I can pass variable to be evaluated as String inside gstring evaluation.
simplest example will be some thing like
def var ='person.lName'
def value = "${var}"
println(value)
I am looking to get output the value of lastName in the person instance. As a last resort I can use reflection, but wondering there should be some thing simpler in groovy, that I am not aware of.
Can you try:
def var = Eval.me( 'new Date()' )
In place of the first line in your example.
The Eval class is documented here
edit
I am guessing (from your updated question) that you have a person variable, and then people are passing in a String like person.lName , and you want to return the lName property of that class?
Can you try something like this using GroovyShell?
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
GroovyShell shell = new GroovyShell( binding )
def result = shell.evaluate( commandString )
Or this, using direct string parsing and property access
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
// Split the command string into a list based on '.', and inject starting with null
def result = commandString.split( /\./ ).inject( null ) { curr, prop ->
// if curr is null, then return the property from the binding
// Otherwise try to get the given property from the curr object
curr?."$prop" ?: binding[ prop ]
}