Preserve leading space in application yaml properties - yaml

I've got a list of properties in yml file
foo:
bar: One., Two., Three
when converting them to list
#Value("\${foo.bar}")
public var listOfBar: List<String> = mutableListOf()
Leading spaces are trimmed so I get
"One." "Two." "Three.", but what I need is " One." " Two." " Three." with spaces before each. Putting '\u0020' in front didn't helped, it got trimmed anyway.

Simply use " around your values:
foo:
bar: " One."," Two."," Three"
Also you can use the explicit list format:
foo:
bar:
- " One."
- " Two."
- " Three"

When you expect List<String> or String[], Spring will split the input string value using , as separator.
To produce the string you want, you need to have the whitespace within quotes (otherwise it is ignored as per the yaml syntax):
foo:
bar: " One., Two., Three"
However, the Spring default converter may call trim() on every token (I don't remember exactly if this is actually the case) simply dropping all your leadin/trailing spaces anyway.
In this case, you may want to register a different converter that doesn't trim or -- far better -- just take the string and split it yourself.

I ended up doing this. And it's worked
#Value("#{'\${foo.bar}'.split(',')}")
public var listOfBar: List<String> = mutableListOf()
and surrounded properties with "
foo:
bar: " One., Two., Three"

Removing spaces like this will break the purpose of trim() for yaml file.
Though I don't understand the use-case in which you may require this. but, I can suggest to use a custom pattern to achieve this as follows:
You can have tokens for spaces required in yaml file:
foo:
bar: $__$One., Two., Three$_$
Have a different class just to retrieve the configs:
public class Configs {
#Value("${foo.bar}")
private List<String> yourList;
public List<String> getYourList(){
// before returning, replace $_$ with space in yourList
}
Use it in your code
class UseHere {
#Autowired
private Configs configs;
...
// read as follows
configs.getYourList().get(0);
...
}

Related

Sping-Boot Config: How to keep whitespace in yaml key being used to populate Map<String, String>

Let's say we have a configuration properties class:
#ConfigurationProperties(prefix = "whitespace.test")
public class WhitespaceTestConfig {
private Map<String, String> configs;
public Map<String, String> getConfigs() {
return configs;
}
public void setConfigs(Map<String, String> configs) {
this.configs = configs;
}
}
and we try to configure it with a key with space included in it:
whitespace.test.configs:
Key With Whitespace: "I am a value with whitespace in it"
Seems as through spring can parse this yaml fine, and it is apparently valid yaml. However, spring (SnakeYaml?) removes the spaces in the Key string:
KeyWithWhitespace -> I am a value with whitespace in it
An easy solution is to designate a special character for space and replace it within the application, but I was wondering if spring already handled this in some fashion? Perhaps there is a way to escape a space in the config in such a way that spring (SnakeYaml?) knows the we want to keep it, or perhaps there is a way to configure this?
For the sake of completeness I've tried using single and double quotations as well as \s \b.
Update:
After some additional research I found an example from SnakeYaml repository that seems to indicate that what I'm looking for should be possible: https://bitbucket.org/asomov/snakeyaml/wiki/Documentation#markdown-header-block-mappings
Specifically this example:
# YAML
base armor class: 0
base damage: [4,4]
plus to-hit: 12
plus to-dam: 16
plus to-ac: 0
# Java
{'plus to-hit': 12, 'base damage': [4, 4], 'base armor class': 0, 'plus to-ac': 0, 'plus to-dam': 16}
In the example the spaces persist in the keys. Unfortunately, I'm at a loss with regard to figuring out where the whitespace is actually getting removed.
For map keys with special characters you need to surround the key with '[]' for the key to be used as specified.
So, in your case it will be
whitespace.test.configs:
'[Key With Whitespace]': "I am a value with whitespace in it"
The new binder is much stricter about property names which means you need to surround them in square brackets. Try the following:
shiro:
testMap:
"[/test1]": test1
"[/test2]": test2

Extracting part of a string on jenkins pipeline

I am having some trouble with the syntax in my pipeline script.
I am trying to capture everything after the last forward slash "/" and before the last period "." in this string git#github.com:project/access-server-pd.git (access-server-pd)
Here (below) is how I would like to set it up
MYVAR="git#github.com:project/access-server-pd.git"
NAME=${MYVAR%.*} # retain the part before the colon
NAME=${NAME##*/} # retain the part after the last slash
echo $NAME
I have it current set up with triple quotes on the pipeline script:
stage('Git Clone') {
MYVAR="$GIT_REPO"
echo "$MYVAR"
NAME="""${MYVAR%.*}"""
echo "$NAME"
But I am receiving an unexpected token on "." error. How might I write this so that I can get this to work?
UPDATE: This command does the trick:
echo "git#github.com:project/access-server-pd.git" | sed 's#.*/\([^.]*\).*#\1#'
Now I just need to find the proper syntax to create a variable to store that value.
In this case, it looks like using a few Groovy/Java methods on the String can extract the parts.
final beforeColon = url.substring(0, url.indexOf(':')) // git#github.com
final afterLastSlash = url.substring(url.lastIndexOf('/') + 1, url.length()) // project/access-server-pd.git
This uses a few different methods:
public int String.indexOf(String str, int fromIndex)
public String String.substring(int beginIndex, int endIndex)
public int String.length()
public int String.lastIndexOf(String str)
You do need to be careful about the code you use in your pipeline. If it is sandboxed it will run in a protected domain where every invocation is security checked. For example, the whitelist in the Script Security Plugin whitelists all of the calls used above (for example, method java.lang.String lastIndexOf java.lang.String).
Performing String manipulation in your pipeline code is perfectly reasonable as you might make decisions and change your orchestration based on it.

Replacing scan by gsub in Ruby: how to allow code in gsub block?

I am parsing a Wiki text from an XML dump, for a string named 'section' which includes templates in double braces, including some arguments, which I want to reorganize.
This has an example named TextTerm:
section="Sample of a text with a first template {{TextTerm|arg1a|arg2a|arg3a...}} and then a second {{TextTerm|arg1b|arg2b|arg3b...}} etc."
I can use scan and a regex to get each template and work on it on a loop using:
section.scan(/\{\{(TextTerm)\|(.*?)\|(.*?)\}\}/i).each { |item| puts "1=" + item[1] # arg1a etc.}
And, I have been able to extract the database of the first argument of the template.
Now I also want to replace the name of the template "NewTextTerm" and reorganize its arguments by placing the second argument in place of the first.
Can I do it in the same loop? For example by changing scan by a gsub(rgexp){ block}:
section.gsub!(/\{\{(TextTerm)\|(.*?)\|(.*?)\}\}/) { |item| '{{NewTextTerm|\2|\1}}'}
I get:
"Sample of a text with a first template {{NewTextTerm|\\2|\\1}} and then a second {{NewTextTerm|\\2|\\1}} etc."
meaning that the arguments of the regexp are not recognized. Even if it worked, I would like to have some place within the gsub block to work on the arguments. For example, I can't have a puts in the gsub block similar to the scan().each block but only a string to be substituted.
Any ideas are welcome.
PS: Some editing: braces and "section= added", code is complete.
When you have the replacement as a string argument, you can use '\1', etc. like this:
string.gsub!(regex, '...\1...\2...')
When you have the replacement as a block, you can use "#$1", etc. like this:
string.gsub!(regex){"...#$1...#$2..."}
You are mixing the uses. Stick to either one.
Yes, changing the quote by a double quote isn't enough, #$1 is the answer. Here is the complete code:
section="Sample of a text with a first template {{TextTerm|arg1a|arg2a|arg3a...}} and then a second {{TextTerm|arg1b|arg2b|arg3b...}} etc."
section.gsub(/\{\{(TextTerm)\|(.*?)\|(.*?)\}\}/) { |item| "{{New#$1|#$3|#$2}}"}
"Sample of a text with a first template {{NewTextTerm|arg2a|arg3a...|arg1a}} and then a second {{NewTextTerm|arg2b|arg3b...|arg1b}} etc."
Thus, it works. Thanks.
But now I have to replace the string, by a "function" returning the changed string:
def stringreturn(arg1,arg2,arg3) strr = "{{New"+arg1 + arg3 +arg2 + "}}"; return strr ; end
and
section.gsub(/\{\{(TextTerm)\|(.*?)\|(.*?)\}\}/) { |item| stringreturn("#$1","|#$2","|#$3") }
will return:
"Sample of a text with a first template {{NewTextTerm|arg2a|arg3a...|arg1a}} and then a second {{NewTextTerm|arg2b|arg3b...|arg1b}} etc."
Thanks to all!
There is probably a better way to manipulate arguments in MediaWiki templates using Ruby.

Spring Validation using Annotation #RegExp

Im using Spring form validation to validate the input fields entered by the user. I need help to include space in a particular field. Below is the validation annotation that Im using. But it does not seem to allow space.
#RegExp(value="([0-9|a-z|A-Z|_|$|.])*",message="value can contain only digits,alphabets or _ or . or $")
private String cName ;
I would like to know what value I need to include in the validation annotation to include space in the name
I tried to include '\s' in the exp value to include blank space. But it doesn't seem to work
Any help on this is much appreciated.
Your regex String is not valid for your requirement.
Use the following regex instead:
//([0-9|a-z|A-Z|\\_|\\$|\\.|\\s])+
#Test
public void testRegex() {
String r = "([0-9|a-z|A-Z|\\_|\\$|\\.|\\s])+";
assertTrue("Allows space", Pattern.matches(r, "test test"));
assertTrue("Allows .", Pattern.matches(r, "12My.test"));
assertTrue("Allows _", Pattern.matches(r, "My_123"));
assertTrue("Allows $", Pattern.matches(r, "$ 1.0"));
}

Rails String Interpolation in a string from a database

So here is my problem.
I want to retrieve a string stored in a model and at runtime change a part of it using a variable from the rails application. Here is an example:
I have a Message model, which I use to store several unique messages. So different users have the same message, but I want to be able to show their name in the middle of the message, e.g.,
"Hi #{user.name}, ...."
I tried to store exactly that in the database but it gets escaped before showing in the view or gets interpolated when storing in the database, via the rails console.
Thanks in advance.
I don't see a reason to define custom string helper functions. Ruby offers very nice formatting approaches, e.g.:
"Hello %s" % ['world']
or
"Hello %{subject}" % { subject: 'world' }
Both examples return "Hello world".
If you want
"Hi #{user.name}, ...."
in your database, use single quotes or escape the # with a backslash to keep Ruby from interpolating the #{} stuff right away:
s = 'Hi #{user.name}, ....'
s = "Hi \#{user.name}, ...."
Then, later when you want to do the interpolation you could, if you were daring or trusted yourself, use eval:
s = pull_the_string_from_the_database
msg = eval '"' + s + '"'
Note that you'll have to turn s into a double quoted string in order for the eval to work. This will work but it isn't the nicest approach and leaves you open to all sorts of strange and confusing errors; it should be okay as long as you (or other trusted people) are writing the strings.
I think you'd be better off with a simple micro-templating system, even something as simple as this:
def fill_in(template, data)
template.gsub(/\{\{(\w+)\}\}/) { data[$1.to_sym] }
end
#...
fill_in('Hi {{user_name}}, ....', :user_name => 'Pancakes')
You could use whatever delimiters you wanted of course, I went with {{...}} because I've been using Mustache.js and Handlebars.js lately. This naive implementation has issues (no in-template formatting options, no delimiter escaping, ...) but it might be enough. If your templates get more complicated then maybe String#% or ERB might work better.
one way I can think of doing this is to have templates stored for example:
"hi name"
then have a function in models that just replaces the template tags (name) with the passed arguments.
It can also be User who logged in.
Because this new function will be a part of model, you can use it like just another field of model from anywhere in rails, including the html.erb file.
Hope that helps, let me know if you need more description.
Adding another possible solution using Procs:
#String can be stored in the database
string = "->(user){ 'Hello ' + user.name}"
proc = eval(string)
proc.call(User.find(1)) #=> "Hello Bob"
gsub is very powerful in Ruby.
It takes a hash as a second argument so you can supply it with a whitelist of keys to replace like that:
template = <<~STR
Hello %{user_email}!
You have %{user_voices_count} votes!
Greetings from the system
STR
template.gsub(/%{.*?}/, {
"%{user_email}" => 'schmijos#example.com',
"%{user_voices_count}" => 5,
"%{release_distributable_total}" => 131,
"%{entitlement_value}" => 2,
})
Compared to ERB it's secure. And it doesn't complain about single % and unused or inexistent keys like string interpolation with %(sprintf) does.

Resources