Ruby HERE-DOC method parameter passing - ruby

I am trying to use a custom method with here-doc and want to pass parameter (there is no business case, I am merely trying to learn ruby). Is there a way to pass parameter in this case? This is what I have so far.
Simple method, just works fine.
def meth1
self.upcase
end
str1 = <<MY.meth1
i am a small case string
MY
# "I AM A SMALL CASE STRING\n"
Now, I thought let us drop some parameters and tried different variations and irb gives me a blank stare.
#variation 1
def meth2( <<EOF1, <<EOF2 )
EOF1.upcase + "..." + EOF2.downcase
end
str2 = <<MY.meth2
some string
EOF1
ANOTHER STRING
EOF2
MY

My guess is that this is what you are trying to do:
def meth2(str1, str2)
str1.upcase + "..." + str2.downcase
end
str2 = meth2(<<EOF1, <<EOF2)
some string
EOF1
ANOTHER STRING
EOF2
str2 # => " SOME STRING\n... another string\n"
If you don't intent to indent, see here. ← See my play with words here?

try something along the lines of
something = "bananas"
str = <<EOF
this has some #{something} in!
EOF

Try something like this:
def meth2( item1, item2 )
item1.upcase + "..." + item2.downcase
end
str2 = meth2 <<EOF1, <<EOF2
some string
EOF1
ANOTHER STRING
EOF2
The problem you are having is due to not fully understanding how heredoc-style string literals work. The <<DELIMITER part just is telling the parser to get it's string data from the lines that follow it. If there is more than one <<DELIMITER on a line, then they stack, and are read in in sequence. So, in this case, the code above is exactly equivalent to:
def meth2( item1, item2 )
item1.upcase + "..." + item2.downcase
end
str2 = meth2 " some string\n", " ANOTHER STRING\n"
Most importantly, there is no way to build a heredoc into a function like you were trying to do there... They can only be used in the same places and manner that other String literals, such as "double quoted" or 'single quoted' literals, can be used.

Related

Call a function within Quotes " "

I am a beginner in Ruby. Could someone help me with this?
I want to call a method within ""
def callme
"this string" # this is usually a path that I want to source from a single location
end
v= "string + callme "
how do I call the function within quotes here? The quotes are essential for my code.
You can use string interpolation / concatenation:
def hi
'Hello'
end
def world
'World'
end
# Concatenation
hi + ' ' + world #=> "Hello World"
# Interpolation
"#{hi} #{world}" #=> "Hello World"
See this answer for more details
If I understand correctly, what you are looking for is string interpolation. The syntax for this is #{...}, like so:
v= "string + #{callme} "
This sets the variable v to "string + this string ".
Reference

How to replace a specific character in a string along with the immediate next character

I have a string of text:
string = "%hello %world ho%w is i%t goin%g"
I want to return the following:
"Hello World hoW is iT goinG
The % sign is a key that tells me the next character should be capitalized. The closest I have gotten so far is:
#thing = "%this is a %test this is %only a %test"
if #thing.include?('%')
indicator_position = #thing.index("%")
lowercase_letter_position = indicator_position + 1
lowercase_letter = #thing[lowercase_letter_position]
#thing.gsub!("%#{lowercase_letter}","#{lowercase_letter.upcase}")
end
This returns:
"This is a Test this is %only a Test"
It looks like I need to iterate through the string to make it work as it is only replacing the lowercase 't' but I can't get it to work.
You can do this with gsub and a block:
string.gsub(/%(.)/) do |m|
m[1].upcase
end
Using a block allows you to run arbitrary code on each match.
Inferior to #tadman, but you could write:
string.gsub(/%./, &:upcase).delete('%')
#=> "Hello World hoW is iT goinG

Smart conversion of double to single quotes in ruby

Problem
In a source file, I have a large number of strings. Some with interpolation, some with special symbols and some with neither.
I am trying to work out if I can replace the simple strings' double quotes with single quotes whilst leaving double quotes for the interpolated and special symbol strings. I would then run this conversion on one or more source code files.
I imagine there is probably a nice regex for this, but I can't quite formulate it.
Example - Code
Imagine the following code:
def myfunc(var, var2 = "abc")
s = "something"
puts "a simple string"
puts "string with a single ' quote"
puts "string with a newline \n"
puts "my #{var}"
end
Example - Result
I would like to turn it into this:
def myfunc(var, var2 = 'abc')
s = 'something'
puts 'a simple string'
puts "string with a single ' quote"
puts "string with a newline \n"
puts "my #{var}"
end
If anyone has any ideas I'd be very grateful!
Assuming that you can read your string from your file by yourself into an array strings:
strings = [ "\"a simple string\"",
"\"string with a single ' quote\"",
"\"string with a newline \n\""
"\"my \#{var}\"" ]
then we would eval them to see how they behave:
$SAFE = 4
single_quoted_when_possible = strings.map { |double_quoted|
begin
string = eval( double_quoted ) # this string, as Ruby sees it
raise unless string.is_a? String
raise unless '"' + string + '"' == double_quoted
rescue
raise "Array element is not a string!"
end
begin
raise unless eval( "'#{string}'" ) == string
"'#{string}'"
rescue
double_quoted
end
}
And that SAFE level 4 is just woodoo, just an acknowledgement from me that we are doing something dangerous. I do not know to what extent it actually protects against all dangers.
In your particular case, you can create a Regexp heuristic, relying on hope that nobody will write "evil" strings in your code, such as /= *(".+") *$/ or /\w+ *\(* *(".+") *\)* *$/. That heuristic would extract some string suspects, to which you could further apply the method I wrote higher above. But I would still have human look at each replacement, and run tests on the resulting code afterwards.

Passing all arguments at once to a method

I am trying to read arguments from a text file and the pass them all at once to a Ruby method.
The arguments in the text file are properly formatted e.g.:
"path", ["elem1","elem2"], 4,"string"
I intend to make a function call like this:
my_method("path", ["elem1","elem2"], 4,"string")
This hopefully I am trying to achieve like this:
IO.readlines("path").each do |line|
puts "#{line}"
my_method(*line.split(","))
end
The problem is that in the method all the array elements are wrapped in quotes. So my method ends up getting this:
""path"", "["elem1","elem2"]", "4",""string""
Now, this is probably because its an array of strings, but why wrap it with an additional "" when I say *arr?
If I use eval:
IO.readlines("path").each do |line|
puts "#{line}"
my_method(*eval(line))
end
I end up with syntax error, unexpected ',' after the first argument in "path", ["elem1","elem2"], 4,"string"
How do I achieve passing all the elements to the method at once reading the arguments from a text file
Also since Ruby does not care about types, why do I have to wrap my arguments with "" in the first place. If I don't wrap the argument in a quote, I get undefined variable for main:object error.
I have one solution, but instead of using "," as your delimiter use some other special character as delimiter in the input line.
# Input line in somefile.txt delimited by "||" :
# "path" || ["elem1","elem2"] || 4 || "string"
def my_method(arg1, arg2, arg3, arg4)
path = arg1
arr = arg2.gsub(/([\[\]])/, "").split(",")
number = arg3.to_i
string = arg4
puts "path : #{path} and is #{path.class}"
puts "arr : #{arr} and is #{arr.class}"
puts "number : #{number} and is #{number.class}"
puts "string : #{string} and is #{string.class}"
end
IO.readlines("somefile.txt").each do |line|
my_method(*line.gsub(/[(\\")]/, " ").split("||"))
end
I hope this helped you out. Let me know if you have any problem.
IO.readlines("path").each do |line|
params = line.split(",").each do |param|
param = eval(param)
end
my_method(*params)
end
When you read the line, all params are strings, so to get arrays and integers you might try to eval then first.
the eval tip might be enough to fix your code.
if you pass the param without quotes, the interpreter will understand it as a constant and not as a string. Thats why you get undefined variable. Again, the eval tip should solve this.
OBS: Be careful with eval since it will execute any code, a command to erase the file or even worse (like mess with your computer or server) if the person behind the source of that file knows it.

ruby code for modifying outer quotes on strings?

Does anyone know of a Ruby gem (or built-in, or native syntax, for that matter) that operates on the outer quote marks of strings?
I find myself writing methods like this over and over again:
remove_outer_quotes_if_quoted( myString, chars ) -> aString
add_outer_quotes_unless_quoted( myString, char ) -> aString
The first tests myString to see if its beginning and ending characters match any one character in chars. If so, it returns the string with quotes removed. Otherwise it returns it unchanged. chars defaults to a list of quote mark characters.
The second tests myString to see if it already begins and ends with char. If so, it returns the string unchanged. If not, it returns the string with char tacked on before and after, and any embedded occurrance of char is escaped with backslash. char defaults to the first in a default list of characters.
(My hand-cobbled methods don't have such verbose names, of course.)
I've looked around for similar methods in the public repos but can't find anything like this. Am I the only one that needs to do this alot? If not, how does everyone else do this?
If you do it a lot, you may want to add a method to String:
class String
def strip_quotes
gsub(/\A['"]+|['"]+\Z/, "")
end
end
Then you can just call string.strip_quotes.
Adding quotes is similar:
class String
def add_quotes
%Q/"#{strip_quotes}"/
end
end
This is called as string.add_quotes and uses strip_quotes before adding double quotes.
This might 'splain how to remove and add them:
str1 = %["We're not in Kansas anymore."]
str2 = %['He said, "Time flies like an arrow, Fruit flies like a banana."']
puts str1
puts str2
puts
puts str1.sub(/\A['"]/, '').sub(/['"]\z/, '')
puts str2.sub(/\A['"]/, '').sub(/['"]\z/, '')
puts
str3 = "foo"
str4 = 'bar'
[str1, str2, str3, str4].each do |str|
puts (str[/\A['"]/] && str[/['"]\z/]) ? str : %Q{"#{str}"}
end
The original two lines:
# >> "We're not in Kansas anymore."
# >> 'He said, "Time flies like an arrow, Fruit flies like a banana."'
Stripping quotes:
# >> We're not in Kansas anymore.
# >> He said, "Time flies like an arrow, Fruit flies like a banana."
Adding quotes when needed:
# >> "We're not in Kansas anymore."
# >> 'He said, "Time flies like an arrow, Fruit flies like a banana."'
# >> "foo"
# >> "bar"
I would use the value = value[1...-1] if value[0] == value[-1] && %w[' "].include?(value[0]). In short, this simple code checks whether first and last char of string are the same and removes them if they are single/double quote. Additionally as many as needed quote types can be added.
%w["adadasd" 'asdasdasd' 'asdasdasd"].each do |value|
puts 'Original value: ' + value
value = value[1...-1] if value[0] == value[-1] && %w[' "].include?(value[0])
puts 'Processed value: ' + value
end
The example above will print the following:
Original value: "adadasd"
Processed value: adadasd
Original value: 'asdasdasd'
Processed value: asdasdasd
Original value: 'asdasdasd"
Processed value: 'asdasdasd"

Resources