String concatenation with constants in ruby 2.7.2 - ruby

I'm trying to concatenate a constant into a string but I'm getting syntax error, unexpected unary+, expecting end' (SyntaxError)`
This is an example of what I have to do:
NAME = "Jane"
def a_function
s = 'Hi' + NAME +' !'
puts s
end
I know you can do "Hi #{NAME}!" but in my case the string has to be with single quotes.
How can I achieve this?

You are missing a space between + and ' !'.
This is a special case of confusing Ruby, because a single expression like +x is actually a valid unary expression meaning just x, the same way as +1 means 1.
Because of this it's likely Ruby is interpreting your expression a + b +c, as a + b c, which is invalid, and hence the error.
The fix:
s = 'Hi ' + NAME + ' !'
^------ Note the space here!

Related

Ruby question: syntax error whilst using gets

I am attempting to run the following program, which will give out a simple greeting taking user input. However, whenever I run the code I get the following message:
syntax error, unexpected tSTRING_BEG, expecting do or '{' or '('
I've tried replacing the single quote marks with doubles, and I've also tried placing '()' around the variable names.
puts 'First name: '
first_name = gets.chomp
puts 'Middle name: '
middle_name = gets.chomp
puts 'Surname: '
surname = gets.chomp
puts "Greets to you," + first_name + middle_name + surname "! Welcome to Valhalla!"
#eux already gave a correct answer to the syntax error in your example.
I just want to show another way to generate the expected output. It's a common Ruby idiom to use string interpolation instead of string concatenation. With string interpolation, you can generate your output like this
puts "Greets to you, #{first_name} #{middle_name} #{surname}! Welcome to Valhalla!"
String interpolation has many advantages – as described in this answer and its comments. In the context of your question the pros are:
It is shorter
It is much clearer where to put whitespace
And It is overall easier to read and understand
You missed a + before ! Welcome to Valhalla! at the last line:
puts "Greets to you," + first_name + middle_name + surname + "! Welcome to Valhalla!"

String can't be coerced into Fixnum (TypeError)

I wrote the basic codes below
puts ' Hi there , what is your favorite number ? '
number = gets.chomp
puts number + ' is beautiful '
puts 1 + number.to_i + 'is way better'
But when I run it,I get the error "String can't be coerced into Fixnum (TypeError)". How do I correct this error please?
You cannot add a String to a number. You can add a number to a String, since it is coerced to a String:
'1' + 1
# => "11"
1 + 1
# => 2
1 + '1'
# TypeError!
Since I suspect you want to show the result of adding 1 to your number, you should explicitly cast it to string:
puts (1 + number.to_i).to_s + ' is way better'
or, use string interpolation:
puts "#{1 + number.to_i} is way better"
String can't be coerced into Integer usually happens, when you try to add a string to a number. since you want to add 1 to your number and concatenate it with a string "is way better". you have to explicitly cast the result you got from adding 1 to your number to a string and concatenate it with your string "is way better".
you can update your code to this:
puts (1 + number.to_i).to_s + " " + 'is way better'
Assuming that the numbers are natural numbers:
number = gets.chomp
puts "#{number} is beautiful ", "#{number.succ} is way better"
You might find the results of entering 'xyz' as an input surprising.
This discussion for determining if your input string is a number may be helpful.

Unexpected keyword_end error, yet syntax seems fine

This function is supposed to pull names from a Comma Separated Values file, and place them into an array.
def xprt_csv_to_ary(csv_file)
namecatcher_regex = "/^[\.{1}]([A-Z]+)\.{3}/" # Matches up to char before next name
current_word = 0
names_array = []
while current_word < 5000
if current_word == 0
name = csv_file.readline.match(namecatched_regex)
else
name = csv_file.past_match.match(namecatcher_regex)
end
names_array[current_word] = name
current_word ++
end
return names_array
end
I'm getting the following error:
syntax error, unexpected keyword_end
I would be as happy to be referred to an existing question that solves my problem as to have someone answer me directly.
Your error comes from line:
current_word ++
There's no such syntax in Ruby. It should be:
current_word += 1
What's more, you create your regexp incorrectly. It should be:
namecatcher_regex = /^[\.{1}]([A-Z]+)\.{3}/
There may be some other errors that I didn't notice.
On this line:
current_word ++
You are telling Ruby to add something to current_word, but you never tell it what to add, instead there's an end directly on the next line. You are missing the operand to the unary +. It should be something like
current_word + something_else
or
current_word + +something_else
In Ruby, whitespace is allowed around operators, so
a +
b
# equivalent to a + b, which is equivalent to a.+(b)
and even
+
a
# equivalent to +a, which is equivalent to a.+#()
is perfectly fine, so if you combine the two, you get that
a + +
b
# equivalent to a + +b, which is equivalent to a.+(b.+#())
is also perfectly fine, and since whitespace around operands is perfectly fine but optional,
a+b
and
a ++
b
# equivalent to a + +b as above
is also perfectly fine.
That's why you only get the error on the next line with the end, because only there can Ruby tell that you are missing the operand to the unary prefix + operator.

Smart conversion of single to double quotes in Ruby

Problem
In a source file, I have a large number of strings.ome with interpolation, some with special symbols and some with neither.
I am trying to work out if I can replace the single quotes with double quotes whilst converting escaped single quote characters. I would then run this conversion on one or more source code files.
Example - Code
Imagine the following code:
def myfunc(var, var2 = 'abc')
s = 'something'
puts 'a simple string'
puts 'string with an escaped quote \' in it'
x = "nasty #{interpolated}" + s + ' and single quote combo'
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 an escaped quote ' in it"
x = "nasty #{interpolated}" + s + " and single quote combo"
puts "my #{var}"
end
If anyone has any ideas I'd be very grateful!
You want negative look behind (?<!) operator:
REGEX
(?<!\)'
DEMO
http://regex101.com/r/rN5eE6
EXPLANATION
You want to replace any single quote not preceded by a backslash.
Don't forget to do a find and replace of all \' with '
THERE IS MORE
For this use case, even if it's a simple use case, a ruby parser would perform better.
As Peter Hamilton pointed out, although replacing single quoted strings with double quoted equivalents might seem as an easy task at first, even that cannot be done easily, if at all, with regexen, mainly thanks to the possibility of single quotes in the "wrong places", such as within double-quoted strings, %q literal string constructs, heredocs, comments...
x = 'puts "foo"'
y = %/puts 'foo'/ # TODO: Replace "x = %/puts 'foo'/" with "x = %#puts 'bar'#"
But the correct solution, in this case, is much easier than the other way around (double quoted to single quoted), and actually partially attainable:
require 'ripper'
require 'sorcerer' # gem install sorcerer if necessary
my_source = <<-source
x = 'puts "foo"'
y = "puts 'bar'"
source
sexp = Ripper::SexpBuilder.new( my_source ).parse
double_quoted_source = Sorcerer.source sexp
#=> "x = \"puts \"foo\"\"; y = \"puts 'bar'\""
The reason why I say "partially attainable" is because, as you can see by yourself,
puts double_quoted_source
#=> x = "puts "foo""; y = "puts 'bar'"
Sorcerer forgets to escape double quotes inside formerly single-quoted string. Feel free to submit a patch
to sorcerer's author Jim Weirich that would fix the problem.

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.

Resources