String substitution in Puppet? - ruby

Is it possible to do a string substitution/transformation in Puppet using a regular expression?
If $hostname is "web1", I want $hostname_without_number to be "web". The following isn't valid Puppet syntax, but I think I need something like this:
$hostname_without_number = $hostname.gsub(/\d+$/, '')

Yes, it is possible.
Check the puppet function reference: http://docs.puppetlabs.com/references/2.7.3/function.html
There's a regular expression substitution function built in. It probably calls the same underlying gsub function.
$hostname_without_number = regsubst($hostname, '\d+$', '')
Or if you prefer to actually call out to Ruby, you can use an inline ERB template:
$hostname_without_number = inline_template('<%= hostname.gsub(/\d+$/, "") %>')

In this page:
https://blog.kumina.nl/2010/03/puppet-tipstricks-testing-your-regsubst-replacings-2/comment-page-1/
it is quite well explained and there is a fantastic trick for testing your regular expressions with irb.
Whith this link and the answer of freiheit I could resolve my problem with substitution of '\' for '/'.
$programfiles_sinbackslash = regsubst($env_programfiles,'\','/','G')

Related

String operations and `eval`

I have an AWS lambda function that receives user's code from a browser as a string and runs eval in a sandboxed environment as in a standard REPL. I am not trying to interpolate a string. I am trying to have eval recognize and perform operations on strings.
I am somewhat limited in the operations I can perform. Basic regex replacement is cool, but I don't think I would be able to do anything more involved than that, but perhaps I'm mistaken.
This works for basic arithmetic operations, the creation of class instances, etc. However, it fails to perform string operations properly. When I pass:
eval `("3*4")`
it returns 12, which is great. However, if I pass:
eval(""str:" + " test"")
it fails to return "str: test". In fact it returns nothing.
It has been suggested that I escape the double quotes. In a REPL, replacing all double quotes with escaped ones, such as \", works.
eval("\"str \" + \"test\"") # => "str test"
However, when I try this with AWS, it returns "\"str \" + \"test\"".
I look forward to hearing your responses.
You shouldn't expect eval(""str:" + " test"") to work. The problem is not related to AWS lambda. If you try this on your own machine, using pry or irb, you will get a SyntaxError. That's because your interpreter can't understand that you are only passing one unified string to eval. So you need to escape all quotation marks inside your string:
eval("\"str \" + \"test\"")
If you have tested it in a REPL without escaping, and it worked, it seems that the REPL you are using, somehow changes your input before sending it to interpreter.
I have seemed to find a work around.
To begin, I will first clarify what my issue was. Say a user entered the following:
class Test
attr_accesssor :data
def initialize(data = nil)
#data = data
end
end
Followed by
Test.new(4).data
eval would properly return 4.
Now say, however, that the user instead wrote
Test.new("A nice, fine string").data
eval would return nothing.
I noticed, however, that if I tacked on a .inspect, as shown below:
Test.new("A nice, fine string").data.inspect
I would be returned A nice, fine string.
So my solution was to wrap the entirety of the user's code in parenthesis and then call .inspect.
Which was accomplished by the following line
code = "(" << code << ").inspect"
Thank you to everyone who took the time to help me out. I really appreciate all of the feedback and suggestions.
You need to be careful about string interpolation when using eval on strings:
str = %(This is my String. It's name is string. Now I can eval "Hooray for my string")
eval(str.inspect)
#=> "This is my String. It's name is string. Now I can eval \"Hooray for my string\""
however these will raise errors
eval(str)
#=> SyntaxError: (eval):1: unterminated string meets end of file
eval(puts str) # will output the string but raise an error after it.
#=> This is my String. It's name is string. Now I can eval "Hooray for my string"
# TypeError: no implicit conversion of nil into String
but this will work
eval("puts #{str.inspect}")
#=> This is my String. It's name is string. Now I can eval "Hooray for my string"

Ruby Syntax, using numbers in symbols?

I'm new to ruby and Chef and am running to an issue with syntax when defining attributes in my cookbook. Below is relevant code:
default[:my_cookbook][:stuff] = {
:foo_bar => {
:grok => ['Hi'],
:2grok => ['Bye'],
...
It appears I can't use a number to begin 2grok.. Is there a way to escape this, or what would be the proper syntax to use '2grok'?
If you want to start a symbol with a digit, you need to enclose it in quotes:
:'2grok' => ['Hi']
If you use double quotes, ruby interpolates string inside:
:"#{1 + 1}grok"
Also, you can use percent-notation:
%s{2grok}
Finally, you can get the symbol by calling to_sym method on a String:
'2grok'.to_sym => ['Hi']
Mladen's answer is correct in term of Ruby. You can use a number at the beginning of symbol's name only using quotes. Keep in mind that you will have to use them to access the value from hash too. However you shouldn't use symbols for defining attributes in your cookbooks. Chef Style Guide recommends using strings instead.

Freemarker ruby script template issue

So I am trying to run a ruby script and I have string expansion sections that are being mistaken for freemarker expressions, for example:
puts "Foo bar baz quux #{#awesome}"
In ruby the #{} is valid ruby, and I need Freemarker to ignore it. According to the documentation, I can escape lie this:
#\{#awesome}
But that leaves the backslash in the final output. I tried to do this:
#{r"#{#awesome"}}
But I get an exception saying that a number was expected... According to the docs, this should produce a literal '#{#awesome}'
What gives? Am I doing something wrong?
This will work:
${r"#{#awesome"}}
Your attempt gives error because FreeMarker's #{...} only accepts numbers.

Using the `$` character in `ruby_block` in chef

I want to use the following code in my recipe for ruby_block, but it's not working because of the '$'. The code cannot find $NAME, but it can find NAME. Can you give me a solution?
file.search_file_replace_line("DEFAULT=/etc/default/$NAME","DEFAULT=/etc/default/tomcat7")
search_file_replace_line expects regex as the first argument. And dollar sign is a special symbol within the regular expressions, it means end of the line, basically. So you have to properly escape it if you really want to replace it with something.
This will do the job:
file.search_file_replace_line("DEFAULT=/etc/default/\\$NAME","DEFAULT=/etc/default/tomcat7")

Why is the IRB prompt changing to an askerisk when I try to match this regex?

I am a newbie in Ruby, I'm using version 1.9.3. I have the following regular expression:
/\\\//
As far as I know, it should match a string which has the characters '\' and '/', one following the other, right?
I am using the following code in order to get true in case the regex matches the string or symbol in the far right:
!(regex !~ :"string or symbol to match")
Because using =~ gives me the index of the match and I simply want a boolean. Besides, I'm trying to see how ugly or hackish can Ruby look compared to C :P
When I try to match the symbol :\/ the IRB prompt changes to an asterisk, and returns nothing. Why?
When I try to match the string "\/" my little ugly snippet returns false. Why?
The symbol :\/ is not a valid symbol. You could do :'\/' if you wanted a symbol version of the string '\/'. And when you feed it "\/" it is false because that has double quotes so it is actually the string '/' so you actually want either '\/' or "\\/".
Finally, it's better code and convention to do your test like so:
!!(regex =~ :'\/')
!!(regex =~ '\/')
!!(regex =~ "\\/")

Resources