Using Groovy 3 YamlBuilder with Yaml that contains a hyphen - groovy

I'm trying to write a Groovy 3 script that uses yamlbuilder to write a yaml file. I have it working on almost everything apart from;
execution:
set-props:
url:http://myhouse.net
port:8000
How do I write a map that allows the use of a hyphen in the name? Following my previous work I foolishly tried;
def setprops=[:]
setprops=(["url":"http://myhouse.net","port":"8000"])
execution.set-props=setprops
Which gives me an error 'The LHS of an assignment should be a variable or a field'.
If I just use execution.setprops then it works fine, but of course the resulting yaml from yaml(execution) is invalid.
I think if the set-props was a a key/value pair then it could go into quote and everything would be good. But because it is part of the structure I don't know what needs to be done.

You can use strings as "methods" and the builder will create your
intermediate structures from them:
import groovy.yaml.YamlBuilder
def b = new YamlBuilder()
b.execution {
"set-props"(
url: "..."
)
}
println b
Or to continue on your example: You can create the whole map and use is as argument, where you want to have that content.
def setprops=["set-props": [url:"..."]]
b.execution(setprops)
Both result in:
---
execution:
set-props:
url: "..."
Note that the first version nests via passed closures and then passes in the map. The second bit just passes a nested map.

Related

terraform console: Extra characters after expression

I installed terraform and trying to do eval basic expression.
I am getting weird errors.
e.g what's wrong with this expression?
variable "BN" { default = "X" }
or
x = 3
for loops works but it needs to be wrapped into square brackets.
[ for bn in [1, 2, 3] : "%{if bn == 2} ok %{else} bad ${bn} %{endif}" ]
terraform console makes impression that you made a syntax error, but I think at most it could be semantic one.
As for now this utility looks very limited.
Is there any other place I can play with terraform where?
Of the three examples you shared, only the third one is actually a Terraform language expression. An expression is something that generates a value which you can then assign to a resource type argument.
Your first example is a variable declaration. The string you assigned to its default argument is an example of an expression - a literal string expression - but that overall block declares a new variable in a configuration, so it's not something you can evaluate to produce a value.
Your second example seems to assigning the value 3 to an argument called x, but that doesn't mean anything without some additional context: x would need to be an argument inside a block in order to be meaningful, and even then it wouldn't be an expression, but rather the definition of an argument called x using the expression 3.
If you want to experiment with the Terraform language then the best way to do it is to make a file whose name has the suffix .tf in a new directory, and then run the main Terraform commands terraform init, terraform plan, etc in that directory. The terraform console command is for evaluating hypothetical expressions against your configuration, but until you've actually written a configuration you'll have nothing other than literal values to refer to.

Dynamically generating arguments Clap

I'm trying to figure out how to dynamically generating arguments from input arguments with Clap.
What I'm trying to emulate with Clap is the following python code:
parser = argparse.ArgumentParser()
parser.add_argument("-i", type=str, nargs="*")
(input_args, additional_args) = parser.parse_known_args()
for arg in input_args:
parser.add_argument(f'--{arg}-bar', required=true, type=str)
additional_config = parser.parse_args(additional_args)
So that you can do the following in your command:
./foo.py -i foo bar baz --foo-bar foo --bar-bar bar --baz-bar bar
and have the additional arguments be dynamically generated from the first arguments. Not sure if it's possible to do in Clap but I assumed it was maybe possible due to the Readme stating you could use the builder pattern to dynamically generate arguments[1].
So here is my naive attempt of trying to do this.
use clap::{Arg, App};
fn main() {
let mut app = App::new("foo")
.arg(Arg::new("input")
.short('i')
.value_name("INPUT")
.multiple(true)
.required(true));
let matches = app.get_matches_mut();
let input: Vec<_> = matches.values_of("input").unwrap().collect()
for i in input {
app.arg(Arg::new(&*format!("{}-bar", i)).required(true))
}
}
Which does not obviously having the compiler scream at you for both !format lifetime and app.arg I'm mostly interesting in solving how I could generate new arguments to the app which then could be matched against again. I'm quite new to rust so it's quite possible this is not possible with Clap.
[1] https://github.com/clap-rs/clap
I assumed it was maybe possible due to the Readme stating you could use the builder pattern to dynamically generate arguments[1].
Dynamically generating argument means that, you can .arg with runtime values and it'll work fine (aka the entire CLI doesn't need to be fully defined at compile-time, this distinction doesn't exist in Python as everything is done at runtime).
What you're doing here is significantly more complicated (and specialised, and odd) as you're passing through unknown parameters then re-parsing them.
Now first of all, you literally can't reuse App in clap: most of its methods (very much including get_matches) take self and therefore "consume" the App and return something else, either the original App or a result. Although you can clone the original App before you get_matches it I guess.
But I don't think that's useful here: though I have not tried it should be possible do do what you want using TrailingVarArg: this would collect all trailing arguments into a single positional arg slice (you will probably need AllowLeadingHyphen as well), then you can create a second App with dynamically generated parameters in order to parse that sub-set of arguments (get_matches_from will parse from an iterator rather than the env args, this is useful for testing... or for this exact sort of situations).

display comments in a python script

Is there a way, beside parsing the file, to display the comments in a Python file ?
As in :
d = {
# key value uses
k = v
}
I would display :
# key value uses
in the function __doc__.
Thanks
Python always deletes (and docstrings not at the beginning of a definition). So you'll have to parse the source yourself if you want to extract them.
The standard library's ast module also drops comments, but you could take a look at the tokenize module, which returns them. (However, it doesn't parse, so you'd still need to do some work to associate the comment with its function or class or whatever.)

Why are calls to containsKey() failing for this groovy map?

I imagine I'm screwing something up with these declarations, but I've got a groovy class with a field defined like this:
Map<String, SomeType> _someField = [:]
I do inserts like this:
_someField.put( someStringVariable, someTypeInstance )
...and then later, when I check whether a key I know has been mapped is present, the check fails:
_someField.containsKey( someStringVariable )
The only way I can get this to succeed is by calling toString(), like so:
_someField.containsKey( someStringVariable.toString() )
I'm using the generic declaration of the map so my IDE gives me auto completion on the value types, so I'd really like (I think) to keep the type information there.
I've tried changing the key type from String to GString, but to no avail. I've tried changing the map initialization from the groovy shorthand [:] to new LinkedHashMap<>, also to no avail.
Any ideas whether I can keep the type information and avoid having to use toString()?
So this was a case where the variable being fed to containsKey() in the instances where it is failing were of type org.codehaus.groovy.runtime.GStringImpl because they were generated by a function that was performing variable expansion on map values, and that function was creating groovy interpolated strings for values instead of Java Strings.
A quick check on the type of the variable confirmed the type problem, and then it was just a matter of tracking back to find the source of the interpolated string.

Prolog List of Constants to String

i have a list in input: [asd,qweqwe,fsdf,lkasd]
As un can see from the code i want connect each constant of the list to output a single variable list.
i m using yap prolog, i consult this code and i write :- run.
the write function print out _G1233 and not 'asd,asd2,asd3,asd4'
why ? how i have to change the code for output me 'asd,asd2,asd3,asd4' ?
run :- toAtomicVars([asd,asd2,asd3,asd4],',',Out),
write(Out),nl.
toAtomicVars([],In,Out).
toAtomicVars([A|B],In,Out) :-
atomic_concat(A,In,Out1),
atomic_concat(',',Out1,Out2),
toAtomicVars(B,Out2,Out2).
you (should) get a warning like
Singleton variables: [In,Out]
Singleton variables: [Out]
that means that you dont really do anything with those variables:
toAtomicVars([],In,Out).
In and Out can be anything, so prolog just prints a dummy value, _Gsomething that means that the variable is not instantiated.
same thing happens in the second clause:
toAtomicVars([A|B],In,Out) :-
atomic_concat(A,In,Out1),
atomic_concat(',',Out1,Out2),
toAtomicVars(B,Out2,Out2).
you dont say anywhere what is that Out.
personally i think that it would be easier if you just printed each variable recursively and then print a comma, something like:
print_list([X]):-
write(X).
print_list([H|T]):-
write(H),
write(', '),
print_list(T).
but if you want to put commas in the list you should add a rule that defines Out.

Resources