Groovy template - code generation - templates

I am asking for advice and opition as of the code to use with groovy templates.
All template examples on the web used a very limited logic but I simply cannot overcome that barrier and the code in my template is substantial.
Is this acceptable? What could be a better way to do this?
Thanks
Peter
The task is to generate TCL type code - specifically if then/elsif/else type contraint
if { [streq $pm_enrichment('a1') "'aaaa2'"] && [strlen $pm_enrichment('aaaa3')] &&\
[strlen $pm_enrichment('aaaa4') ] } {
set pm_enrichment('ResultAAA') 0
}
elseif { [streq $pm_enrichment('b1') "'bb2'"] && [strlen $pm_enrichment('bbb3')] &&\
[strlen $pm_enrichment('bbbb4') ] } {
set pm_enrichment('ResultBBB') 1
}
else { [streq $pm_enrichment('c1') "'cc2'"] && [strlen $pm_enrichment('ccc3')] &&\
[strlen $pm_enrichment('cccc4') ] } {
set pm_enrichment('ResultCCC') 2G
}
//////////////////////////////////////
def dataCasesClosure= {->
pos=0
arrSorted = []
mapStmt.each{arrSorted.add(it.key) }
arrSorted = arrSorted.sort()
outStr=''''''
arrSorted.each { i ->
tmpStatement = statement
tmpResultStmt = resultStmt
list=mapStmt[i]
resultList=mapResultStmt[i]
pos=0
int index = tmpStatement.indexOf(keyword);
while (index >=0){
val = list[pos].replaceAll(~'"','')
pos +=1
tmpStatement=tmpStatement.replaceFirst( ~/#/,/${val}/)
index = tmpStatement.indexOf(keyword, index+keyword.length()) ;
}
if (tmpStatement ==~/\W+$/) {
tmpStatement=tmpStatement[0..-2]
}
pos=0
index = tmpResultStmt.indexOf(keyword);
while (index >=0){
val = resultList[pos]
pos +=1
tmpResultStmt=tmpResultStmt.replaceFirst( ~/#/,/${val}/)
index = tmpResultStmt.indexOf(keyword, index+keyword.length()) ;
}
if (i==0) {
outStr= "if {${tmpStatement} } { \n\t\t ${tmpResultStmt} \n }"
} else if (i < arrSorted.size()-1 ){
outStr += "elseif {${tmpStatement} } { \n\t\t ${tmpResultStmt} \n }"
} else {
outStr += "else {${tmpStatement} } { \n\t\t ${tmpResultStmt} \n }"
}
}
outStr
} // ### dataCasesClosure
def valuesIfThenStmt= [
"statement":dataCasesClosure
]
tplIfThenStmt = '''
##############################
${statement}
'''
def engine = new SimpleTemplateEngine()
templateResult = engine.createTemplate(tplIfThenStmt).make(valuesIfThenStmt)
println templateResult.toString()

If this is all you have to generate, the template is overkill. You could have just called the dataCasesClosure directly to get its output.
Assuming it is part of a larger template then, I think it is very reasonable to use closures to produce output for a particularly complex parts, just as you have done. I have personally done this on an extreme scale with good results.

Related

split a string by commas, but commas in a token

Let's say I have this:
something,"another thing"
This can be split easily with a normal split function.
Now I want to have more complicated syntax and I do:
something,"in a string, oooh",rgba(4,2,0)
This does not work with a regular split function.
I tried using things like replacing commas inside of specific types of tokens, but that became too over-complicated and I feel there has to be a better way.
Then I tried with regular expressions, which worked, until I had to add a new feature, which wouldn't work with the regexp I had (which was pretty bad), also regexp matches can be slow, and this is supposed to be as fast as possible.
What would be a better way to solve this?
Here is the source repo for extra context https://github.com/hyprland-community/hyprparse
And the format in question is the hyprland config format
Iterate over the string keeping a context state:
None
Inside a "..."
Inside a (...)
Inside a context, comma has no separator meaning.
Limitations: This is a midnight hack!
See also Rust Playground
fn split(s: String) -> Vec<String> {
let mut context = None;
let mut i = 0;
let mut start = 0;
let mut items = Vec::new();
for c in s.chars() {
if context == Some('"') {
if c == '"' {
context = None;
}
i = i+1;
continue;
} else if context == Some('(') {
if c == ')' {
context = None;
}
i = i+1;
continue;
}
if c == '"' || c == '(' {
context = Some(c);
}
if c == ',' && context.is_none() {
items.push(s[start..i].to_string());
start = i + 1;
}
i = i+1;
}
items.push(s[start..i].to_string());
items
}
fn main() {
let s = "something,\"in a string, oooh\",rgba(4,2,0)".to_string();
println!("{:?}", split(s));
// -> ["something", "\"in a string, oooh\"", "rgba(4,2,0)"]
}
Thanks for all the help everyone, I eventually came up with my own solution with the help of people I knew IRL, here is my solution:
fn previous_rgb(index: usize, chars: Vec<char>) -> bool {
let string: String = chars[index-3..index].iter().collect();
let string = string.as_str();
if string == "gba" || string == "rgb" {
true
} else {
false
}
}
fn splitter<Str: ToString>(s: Str) -> Vec<String> {
let mut is_in_rgb = false;
let mut is_in_str = false;
let mut last = 0;
let chars: Vec<_> = s.to_string().chars().collect();
let mut final_str = vec![];
for (index, c) in chars.iter().enumerate() {
if *c == '(' && previous_rgb(index, chars.clone()) && !is_in_str {
is_in_rgb = true;
} else if *c == ')' && is_in_rgb && !is_in_str {
is_in_rgb = false;
} else if *c == '"' && is_in_str {
is_in_str = false;
} else if *c == '"' && !is_in_str {
is_in_str = true;
} else if *c == ',' && !is_in_str && !is_in_rgb {
final_str.push(chars[last..index].iter().collect());
last = index + 1
};
}
final_str.push(chars[last..].iter().collect());
final_str
}
fn main() {
let splitted = splitter(r#"test,test: rgba(5,4,3),"test2, seperated""#);
println!("{splitted:?}");
}

recheck outer if boolean true or false within it's else

My goal is to recheck variable coolFeature boolean value from it's else
if (coolFeature) { // want to run this again after value becomes true in else below
$("#Editor").data("kendoWindow").width = '600';
$("#Editor").data("kendoWindow").title("Format Feature - " + Type + ' #' + graphic.attributes.OBJECTID);
$('#ndt').hide();
} else {
$("#Editor").data("kendoWindow").title("Edit Attributes - " + Type + ' #' + graphic.attributes.OBJECTID);
$('#ndt').show();
$("#ndt").click(function() {
$(this).data('clicked', true);
$("#Editor").data("kendoWindow").hide();
coolFeature = "true"; // want to reset to True here, then run the actions under initial if
});
}
I think you need simple recursion, I can't see the entire code so I can't tell exactly.
var myFunction = function(coolFeature) {
if(coolFeature) {
console.log("Cool");
} else {
myFunction(true);
}
};
myFunction(false);

Parsing custom structured file with PyParsing

I'm need of help parsing a custom file structured file. As you can see below is the structure. The issue is that I can't seem to parse the structure correctly, namely myOriginalFormula & myBonusType in the same group when I want them seperated for example.
AttributeDictionary SomeDictName
{
myAttributeDefinitionCategories
{
AttributeDefinitionList SomeList
{
AttributeDefinition SomeDefinitioName < uid=8972789HHDUAI7 >
{
myOriginalFormula "(A_Variable) * 10"
myBonusType FlatValue
}
AttributeDefinition UIBlankAttribute < uid=JIAIODJ7899 >
{
}
AttributeDefinition SomeOtherDefinitionName < uid=17837HHJAJ7788 >
{
myOriginalFormula 1
mySpecializations
{
Specialization "Some_Specialization 1"
{
myCondition "Something.MustEqual = 1"
myFormula 0
}
Specialization "SomeSpecialization 2"
{
myCondition "Something.MustEqual = 2"
myFormula 0.026
}
}
myBonusType FlatValue
}
AttributeDefinition SomeReal_Other_definition < uid=6768GYAG//() >
{
myOriginalFormula "(Some_Formula / Other_Variable) - 1"
myBonusType Percentage
myUINumDecimals 1
myHasAddSignUI FALSE
}
}
}
}
My try is blow. Could someone help me parse this structure correctly?
def syntaxParser():
# constants
left_bracket = Literal("{").suppress()
right_bracket = Literal("}").suppress()
semicolon = Literal(";").suppress()
space = White().suppress()
key = Word(alphanums + '_/"')
value = CharsNotIn("{};,")
# rules
assignment = Group(key + Optional(space + value))
block = Forward()
specialblock = Forward()
subblock = ZeroOrMore(Group(assignment) | specialblock)
specialblock = (
Keyword("Specialization")
+ key
+ left_bracket
+ subblock
+ right_bracket)
block << Group(
Optional(Group(key + Optional(space + value)))
+ left_bracket
+ Group(ZeroOrMore(assignment | Group(block) | Group(specialblock)))
+ right_bracket)
script = block
return script
Your definition of value is too greedy:
value = CharsNotIn("{};,")
I don't know how this works with the format you are parsing, but I get better results with this:
value = quotedString | CharsNotIn("{};,\n")

Exporting CSS Rules with awk

I'm trying to export a css rule from a css file with awk but I am not able to do it. I need only the rules containing the "background-image" line.
#rule{
...
background-image: url(path);
}
Here's what I have tried so far:
awk '/^[#].*{.*background-image.*/','/}/' css/file.css
What am I doing wrong?
At this moment I got the best result using:
/^[#A-Za-z.]/ { accum = 1; }
accum == 1 { css = css $0 "\n"; }
accum == 1 && /background-image/ { found = 1; }
/\}/ { accum = 0; if (found == 1) print css; found = 0; css = ""; }
and it allows me to get a full block with all the selectors
Turn accumulation on after matching an open brace. Accumulate all lines while flag is on. Turn off after closing brace is seen. Print only if background-image found during accumulation. If you want to include lines before the match you do do something like this.
{ line4 = line3; line3 = line2; line2 = line1; line1 = $0 "\n"; }
/\{/ { accum = 1; head = line4 line3 line2 line1; }
accum == 1 { css = css $0 "\n"; }
accum == 1 && /background-image/ { found = 1; }
/\}/ {
accum = 0;
if (found == 1) print head css;
found = 0; css = "";
}
You had said in comments "I need the full block from # (or . ) to }" but I'm getting the impression that you really just want this.
/\{/ { selector = $0 }
/background-image/ { print selector "\n" $0 "\n}\n" }

Fuzzy Matches on dijit.form.ComboBox / dijit.form.FilteringSelect Subclass

I am trying to extend dijit.form.FilteringSelect with the requirement that all instances of it should match input regardless of where the characters are in the inputted text, and should also ignore whitespace and punctuation (mainly periods and dashes).
For example if an option is "J.P. Morgan" I would want to be able to select that option after typing "JP" or "P Morgan".
Now I know that the part about matching anywhere in the string can be accomplished by passing in queryExpr: "*${0}*" when creating the instance.
What I haven't figured out is how to make it ignore whitespace, periods, and dashes. I have an example of where I'm at here - http://jsfiddle.net/mNYw2/2/. Any help would be appreciated.
the thing to master in this case is the store fetch querystrings.. It will call a function in the attached store to pull out any matching items, so if you have a value entered in the autofilling inputfield, it will eventually end up similar to this in the code:
var query = { this.searchAttr: this.get("value") }; // this is not entirely accurate
this._fetchHandle = this.store.query(query, options);
this._fetchHandle.then( showResultsFunction );
So, when you define select, override the _setStoreAttr to make changes in the store query api
dojo.declare('CustomFilteringSelect', [FilteringSelect], {
constructor: function() {
//???
},
_setStoreAttr: function(store) {
this.inherited(arguments); // allow for comboboxmixin to modify it
// above line eventually calls this._set("store", store);
// so now, 'this' has 'store' set allready
// override here
this.store.query = function(query, options) {
// note that some (Memory) stores has no 'fetch' wrapper
};
}
});
EDIT: override queryEngine function as opposed to query function
Take a look at the file SimpleQueryEngine.js under dojo/store/util. This is essentially what filters the received Array items on the given String query from the FilteringSelect. Ok, it goes like this:
var MyEngine = function(query, options) {
// create our matching query function
switch(typeof query){
default:
throw new Error("Can not query with a " + typeof query);
case "object": case "undefined":
var queryObject = query;
query = function(object){
for(var key in queryObject){
var required = queryObject[key];
if(required && required.test){
if(!required.test(object[key])){
return false;
}
}else if(required != object[key]){
return false;
}
}
return true;
};
break;
case "string":
/// HERE is most likely where you can play with the reqexp matcher.
// named query
if(!this[query]){
throw new Error("No filter function " + query + " was found in store");
}
query = this[query];
// fall through
case "function":
// fall through
}
function execute(array){
// execute the whole query, first we filter
var results = arrayUtil.filter(array, query);
// next we sort
if(options && options.sort){
results.sort(function(a, b){
for(var sort, i=0; sort = options.sort[i]; i++){
var aValue = a[sort.attribute];
var bValue = b[sort.attribute];
if (aValue != bValue) {
return !!sort.descending == aValue > bValue ? -1 : 1;
}
}
return 0;
});
}
// now we paginate
if(options && (options.start || options.count)){
var total = results.length;
results = results.slice(options.start || 0, (options.start || 0) + (options.count || Infinity));
results.total = total;
}
return results;
}
execute.matches = query;
return execute;
};
new Store( { queryEngine: MyEngine });
when execute.matches is set on bottom of this function, what happens is, that the string gets called on each item. Each item has a property - Select.searchAttr - which is tested by RegExp like so: new RegExp(query).test(item[searchAttr]); or maybe a bit simpler to understand; item[searchAttr].matches(query);
I have no testing environment, but locate the inline comment above and start using console.debug..
Example:
Stpre.data = [
{ id:'WS', name: 'Will F. Smith' },
{ id:'RD', name:'Robert O. Dinero' },
{ id:'CP', name:'Cle O. Patra' }
];
Select.searchAttr = "name";
Select.value = "Robert Din"; // keyup->autocomplete->query
Select.query will become Select.queryExp.replace("${0]", Select.value), in your simple queryExp case, 'Robert Din'.. This will get fuzzy and it would be up to you to fill in the regular expression, here's something to start with
query = query.substr(1,query.length-2); // '*' be gone
var words = query.split(" ");
var exp = "";
dojo.forEach(words, function(word, idx) {
// check if last word
var nextWord = words[idx+1] ? words[idx+1] : null;
// postfix 'match-all-but-first-letter-of-nextWord'
exp += word + (nextWord ? "[^" + nextWord[0] + "]*" : "");
});
// exp should now be "Robert[^D]*Din";
// put back '*'
query = '*' + exp + '*';